Visual C++ Programmer's Guide

The Visual C++ Programmer's Guide covers a broad range of subjects, such as programming with C/C++, programming with MFC, and the various primary steps involved in creating your program.
Porting and Upgrading
Beginning Your Program
Using MFC to write Win32 programs
Creating an MFC-based program using a Wizard
Compiling and Linking
Adding User Interface Features
Adding Program Functionality
Debugging Your Program
Performance Tuning, or Profiling
Preprocessor Reference
Language Quick Reference
C Run-Time Library Reference
Build Error Messages

Interesting home pages
Visual C++ Home The entire Visual C++ product.
Sample Programs
Visual C++ User's Guide
Microsoft Foundation Class Library
Visual C++ Tutorials
C/C++ Languages and C++ Libraries
Visual C++ Editions


Porting and Upgrading

Once you have a working application, you can port it to C++, to a different platform, or to another operating system. You can also upgrade a project built in a previous version of Visual C++ to the latest version. These topics describe porting and upgrading procedures and details about code changes and added features in the latest version.
Overviews Short introductions to porting concepts
How Do I Steps to take to port or upgrade your program, or to write portable code
Frequently Asked Questions Common questions about porting
Details Detailed articles about porting, particularly code changes
What do you want to do?
Learn more about the kinds of porting I can do to and from other languages, platforms, operating systems, or versions of Visual C++.
Start porting my own programs
Write code for maximum portability

Interesting pages


Overviews: Porting and Upgrading

Home | How Do I | FAQ | Details

There are many ways to adapt your existing applications.

  • Make them more Internet friendly
    • By upgrading to Active document servers

    • By upgrading to ActiveX controls with asynchronous properties
  • Make their user-interfaces up-to-date
    • By using new ActiveX control features such as transparent and windowless controls

    • By adding Windows 95 functionality
  • Make them more adaptable to many kinds of platforms
    • By using MFC libraries
  • Port from different platforms
    • Differences Between 16-Bit Windows and 32-Bit Windows: Overview

    • Porting Tools, including PORTTOOL
  • Port to other C++ compilers
    • By using the Standard C++ library
  • Port from previous 32-bit versions and 16-bit versions of Visual C++


Upgrading ActiveX Controls: Overview

Home | Overview | How Do I | FAQ | Details

Beginning with Visual C++ 4.2, ActiveX controls can be optimized in several ways: optimizing persistence and initialization, providing windowless activation, turning off ActivateWhenVisible, providing mouse interaction while inactive, flicker-free activation, using an unclipped device context, and optimizing control drawing.

These enhancements minimize control size by requiring fewer interfaces and increase performance by allowing controls to share the container’s window and optimizing drawing and activation. (Typically, creating a window takes 60% of a control’s creation time.) Windowless controls also make it possible to have transparent and nonrectangular controls.

With MFC versions 4.2 and later, you can also load ActiveX control properties asynchronously. For information about adding asynchronous property support to an existing control, see How Do I Update an Existing OLE Control to Use New ActiveX Control Features?.

When you create a new control using the ActiveX ControlWizard, you can choose to include optimizations and asynchronous properties automatically in the wizard-generated code by selecting them in the Advanced Options dialog box. If your control was created with a version of Visual C++ prior to 4.2, you can update your control to take advantage of the new ActiveX control features. For a detailed discussion of how to add these features to an existing control, see ActiveX Controls: Optimization. For detailed information about the MFC member functions that implement these optimizations, see COleControl. The member functions are listed by use, such as Windowless Operations and Inactive Pointer Handling Functions.

When preparing your existing ActiveX control for use on the Internet, there are additional steps needed to make it perform well in an online environment. For details about these, including packaging your code for download, and code signing, see Upgrading an Existing ActiveX Control to be Used on the Internet.


Advantages of Using the MFC Libraries: Overview

Home | Overview | How Do I | FAQ | Details

MFC is the easiest way for you to achieve two kinds of portability:

  • Portability among different operating systems

  • Portability among different processors, such as x86 and DEC Alpha

MFC is designed to wrap your C/C++ applications to work on almost any operating system with little or no modification, including 16-bit and 32-bit Windows and UNIX if a UNIX MFC library is present. MFC is also designed to be completely portable among different processors.

Note that if you want to write ANSI Standard C++ applications, you cannot use the MFC libraries. See Write Code that Works in the Largest Number of C Compilers for help on writing strict ANSI Standard C++.

Advantages of MFC

MFC is an application framework designed for rapid Windows development. Visual C++ for Intel x86, Alpha, and PowerPC are all Windows NT-based. They are designed to be portable among each other. MFC's job is to make C++ code universal on these platforms by wrapping the system dependent code, such as messages, and your applications should port easily among the platforms. In most cases, a Visual C++ application created in the development environment on one of these platforms can be opened in the development environment on another platform and the conversion is done automatically. See Port to and from Non-Intel Platforms.

If you want to develop UNIX applications and your UNIX system has the UNIX version of MFC, your Visual C++ applications should port with no problem. If you want to port your UNIX application to 32-bit windows, see Port from UNIX to Win32.


Differences Between 16-Bit Windows and 32-Bit Windows: Overview

Home | Overview | How Do I | FAQ | Details

The increased address-space size in 32-bit Windows impacts 16-bit code in several ways:

  • Pointers are all 32 bits wide and are no longer near or far, and your code cannot make assumptions based on segmented memory.

  • Window handles, handles to other objects (such as pens, brushes, and menus), and graphics coordinates have increased to 32 bits. Thus, you cannot use types such as WORD interchangeably with HWND as you could in 16-bit Windows.

  • Message handlers must be rewritten because the different sizes can change the way information is packed in some message parameters.

  • The larger size of graphics coordinates affects a number of function calls.

The key areas of 16-bit code affected by these changes are:

  • Window procedure declarations

  • Near and far type declarations

  • Data types

  • Messages

  • Calls to API functions

  • WinMain function

For a thorough discussion of 32-bit adaptations in each of these areas, see Porting 16-Bit Code to 32-Bit Windows.


Porting Tools: Overview

Home | Overview | How Do I | FAQ | Details

Standard Visual C++ comes with the PORTTOOL.EXE porting tool.


PORTTOOL.EXE

You can use the PORTTOOL utility (PORTTOOL.EXE) to port applications more easily. This utility finds locations in your code, such as references to certain API functions and messages, that are likely to need revision.

PORTTOOL utility is in the Samples\Sdk\SdkTools\Porttool directory on the CD, along with its source code. You can examine the source code to better understand how PORTTOOL works, or modify it and rebuild it for your own needs. You can download the utility and its sources from the PORTTOOL sample.

Use the following steps to start using the PORTTOOL utility:

  1. Run PORTTOOL and load a Windows 3.x source file.

  2. From the Search menu, select the SearchAPI option to search for problematic API functions and messages.

When a problem is found, a dialog box is displayed specifying the message or function and suggesting what change is needed. Although the porting tool is not intended to replace your primary editor, it does have basic editing capabilities (such as Cut, Paste, and Search).

PORTTOOL uses settings in the file PORT.INI to determine what items to look for.


Port to the Standard C++ Library: Overview

Home | Overview | How Do I | FAQ | Details

The Standard C++ library is ANSI compliant, which makes your C++ code portable across compilers and platforms. In addition, the Standard C++ library provides extended functionality, such as numerous algorithms that manipulate C++ objects.

In strict ANSI C++, you cannot use the MFC library, and you must disable Microsoft C language extensions.

The Standard C++ library is a set of 51 header files and encompasses all the latest ANSI C++ extensions (as of June 1996), including the Standard Template library and a new iostream library.

The main difference between the Standard C++ library and previous run-time libraries is in the iostream library. Details of the iostream implementation have changed, and you cannot mix calls to the old iostream library and to the new Standard C++ library.

See Porting to the Standard C++ Library for details.


How Do I: Porting and Upgrading

Home | Overview | FAQ | Details

See the following how-to topics to port your existing applications, upgrade to the latest Visual C++, or write code for maximum portability:

Upgrade Existing Visual C++ Applications

  • Previous versions of 32-bit Visual C++

  • Previous versions of 16-bit Visual C++

  • Previous run-time libraries to the Standard C++ library

  • Previous Visual C++ Enterprise Edition projects

Port Visual C++

  • To and from non-Intel platforms

  • To and from non-Visual C++ development environments

  • From other languages

Port or Upgrade ActiveX Controls (Formerly OLE Controls) and Visual Basic Controls

  • Upgrade existing controls to use new ActiveX features

  • Upgrade existing controls to be used on the Internet

  • Port between 16-Bit and 32-Bit ActiveX controls

  • Port Visual Basic controls and existing CDK projects

  • Port ActiveX controls to other applications

Upgrade In-Process Servers

  • To Active document servers

Upgrade WinHelp

  • From previous versions of WinHelp

Design Applications for Maximum Portability

  • Write code that works on the largest number of platforms

  • Write code that works in the largest number of C compilers

  • Write code that is easy to internationalize


Upgrade Previous 32-Bit Versions of Visual C++

Home | Overview | How Do I | FAQ | Details

Projects built in previous 32-bit versions of Visual C++ can be opened and saved in Visual C++ projects automatically.

However, if you have built a 32-bit Visual C++ project from the command line with your own makefile, the Visual C++ development environment does not recognize project data in your file. Instead, the development environment offers to wrap your makefile. If you choose this option, a project is created with one file in it, your makefile, but the project will still build and run within the development environment. See port a project made with NMAKE to the development environment or port a project made without NMAKE to the development environment for step-by-step instructions. To take advantage of wizards and integrated debugging features, it would be better for you to create a new project in the development environment, add your existing files to it, then build and save it as an up-to-date project.

To convert projects built in previous versions of the Visual C++ development environment

  1. From the File menu, click Open Workspace.

    The Open Project Workspace dialog box appears.

  2. In the Files of Type drop-down list, select All Files (*.*) to display all files.

  3. Select the drive and directory containing the previous makefile or project file.

  4. Select the makefile or project file from the list and click Open.

    A message box appears asking if you want to convert to the new project format.

  5. Click Yes.

    A new project workspace file (.DSW) and a new project options file (.OPT) are created with your old project workspace name. In addition a project build file (.DSP) will be created in each project directory for each project in the workspace. For the example of a single-project workspace called MYAPP.MDP, then MYAPP.DSW, MYAPP.DSP, and MYAPP.OPT are created and saved to the same directory. In the more complicated example of a two project workspace called MYAPP2.MDP, which also includes a subproject MYDLL2, then MYAPP2.DSW, MYAPP2.DSP, and MYAPP2.OPT are created and saved to the same directory and MYDLL2.DSP is created in the MYDLL2 directory.

    After the new files are written, the new project workspace opens in the development environment.

  6. To recompile and link your application, click Build or Rebuild All from the Build menu.

You may want or need to modify the new project:

  • To use the Standard C++ iostream library instead of a previous version of the iostream library

  • To work with the current MFC library

Coexisting with Previous Versions of Visual C++

Installing Visual C++ 6.0 overwrites library DLLs and PDBs used by previous Visual C++ versions (4.2 and 5.0). Visual C++ 4.2 and 5.0 cannot read the new-format debugging information in these DLLs. If you need to use Visual C++ 6.0 and Visual C++ 4.2/5.0, you can:

  • Run Visual C++ 6.0 and the older version on separate machines.

  • Run Visual C++ 6.0 and the older version on separate installations of the operating system on the same machine.

  • Use the Visual C++ 6.0 debugger for debugging in the new DLLs.

  • Copy the old versions of the affected files into your Visual C++ 5.0 or 4.2 project Debug directory. (Do this before you install Visual C++ 6.0 or get the old versions from the \MSDEV\DEBUG directory of the Visual C++ 4.2 or 5.0 CD.)

None of these workarounds allow you to debug release builds with the 4.2 or 5.0 debugger.

The affected CRT files are:

  • MSVCRTd.dll

  • MSVCRTd.pdb

  • MSVCIRTd.dll

  • MSVCIRTd.pdb

The affected MFC files are:

  • MFC42d.dll

  • MFC42d.pdb

  • MFC42u.pdb

  • MFC42ud.dll

  • MFC42ud.pdb

  • MFCd42d.dll

  • MFCd42d.pdb

  • MFCd42ud.dll

  • MFCd42ud.pdb

  • MFCn42d.dll

  • MFCn42d.pdb

  • MFCn42ud.dll

  • MFCn42ud.pdb

  • MFCo42d.dll

  • MFCo42d.pdb

  • MFCo42ud.dll

  • MFCo42ud.pdb

Do not replace the new versions of MFC42.dll, MFC42u.dll, and MSVCRT.dll with the older versions. If you do, you may break other applications dependent on the new versions of these DLLs. The Visual C++ 6.0 development environment, for example, requires the current version of MFC42.dll.

If you need to use Visual C++ 6.0 to generate import libraries in Visual C++ 5.0 format, you can use the /LINK50COMPAT option.


Upgrade Previous 16-Bit Versions of Visual C++

Home | Overview | How Do I | FAQ | Details

Projects built in previous 16-bit versions of Visual C++ can be opened and saved in Visual C++ projects automatically.

However, if you have built a 16-bit Visual C++ project from the command line with your own makefile, the development environment does not recognize project data in your file. Instead, the development environment offers to wrap your makefile. If you choose this option, a project is created with one file in it, your makefile, but the project will still build and run within the development environment, assuming it is 32-bit compatible. See port a project made with NMAKE to the development environment or port a project made without NMAKE to the development environment for step-by-step instructions. To take advantage of wizards and integrated debugging features, it would be better for you to create a new project in the development environment, add your existing files to it, then build and save it as an up-to-date project.

To convert projects built in 16-bit Visual C++ to development environment projects

  1. From the File menu, click Open Workspace.

    The Open Project Workspace dialog box appears.

  2. In the Files of Type drop-down list, select All Files (*.*) to display all files.

  3. Select the drive and directory containing the previous makefile.

  4. Select the makefile from the list and click Open.

    A message box is displayed saying that the project will be converted, that project settings will be converted to Win32 equivalents, and asking if you want to convert.

  5. Click Yes.

    A new project workspace file (.DWS) is created with your old makefile name, then written to the same directory as your existing makefile. For example, if your previous project was MYAPP.MAK, then MYAPP.DSW is created and saved to the same directory.

    After the new files are written, the new project workspace opens in the development environment.

To add your 16-bit Visual C++ files to a Visual C++ project

  1. Open the 16-bit project in the development environment as described in the previous procedure.

  2. From the Project menu, click Add ToProject., then click Files from the submenu that appears.

  3. In the Insert Files into Project dialog box, select all your application files and click OK.

    Your application files are now in the Visual C++ development environment project.

To upgrade 16-bit Visual C++ code

  1. Remove VBX controls.

    VBX controls are not supported in a 32-bit application. The CVBControl class, the AfxRegisterVBEvent, AfxGetPict, AfxSetPict, and AfxReferencePict global functions, and the ON_VBXEVENT macro are unavailable with Win32. If you use VBX controls in your application, you must replace them with standard Windows controls or COM controls, redesigning your application as necessary.

  2. Replace difficult-to-port code, such as assembly-language functions and MS-DOS calls, with stubs.

    If your 16-bit application makes calls to an assembly-language module, you should rewrite it in C or C++ if possible. Otherwise, you will be faced with rewriting the assembly-language portion for each hardware platform that can run Win32.

    If you’ve used any MS-DOS services for file I/O, including those used by Windows version 3.x, you will have to rewrite the code using the Win32 file I/O set. If you’ve used the CFile class for file I/O, you are shielded from this change because CFile uses the new function calls even though its member function interface remains unchanged.

  3. Build your application with and note any 32-bit related problems.

  4. Use the information in Porting 16-Bit Code to 32-Bit Windows. Rebuild until the main body of your program is running correctly.

  5. Implement each function that you replaced with a stub in step 2 until the entire application runs correctly.

  6. Remove MFC libraries from the link input list.

    Let the MFC header files automatically link in the correct version of MFC.

You may want or need to modify the new project:

  • To use the Standard C++ iostream library instead of a previous version of the iostream library

  • To work with the current MFC library


Port to the Standard C++ Library

Home | Overview | How Do I | FAQ | Details

The Standard C++ library encompasses all the latest ANSI C++ extensions (as of June 1996), including the Standard Template library and a new iostream library. The Standard C++ library provides new functionality, such as numerous algorithms that manipulate C++ objects, and a migration path for developers who want to move to the standard iostream.

The Standard C++ library is a set of 51 header files. A list of the header files can be found in C++ Library Overview. The new header files do not have the .h extension. The Standard C++ library also has 18 standard C headers with the .h extension, for example, errno.h and stdio.h.

The main difference between the Standard C++ library and previous run-time libraries is in the iostream library. Details of the iostream implementation have changed, and you cannot mix calls to the old iostream library and to the new Standard C++ library.

  • How do I make the Standard C++ library the default?

  • How do I make the old iostream library the default?

  • What problems can I run into when linking an earlier application?


Make the Standard C++ Library the Default

If you want to use the Standard C++ library, include one or more of the Standard C++ library header files in your code, for example:

#include <algorithm>

The C++ Library Overview contains a list of the header files. The new header files do not have the .h extension.

Do not use the old iostream header files (fstream.h, iomanip.h, ios.h, iostream.h, istream.h, ostream.h, streamb.h, and strstrea.h). You cannot mix calls to the old iostream library and the new Standard C++ library.

The Standard C++ library filenames are LIBCP.LIB, LIBCPMT.LIB, and MSVCPRT.LIB. The debug versions are contained in LIBCPD.LIB, LIBCPMTD.LIB, and MSVCPRTD.LIB.

If you include the new Standard C++ header files, the run-time library files that contain the Standard C++ library will be the default libraries. For example, if you choose Multithreaded in the Use run-time library drop-down list in the Code Generation category of the C/C++ tab in the Project Settings dialog box, and you have included a Standard C++ header file in your code, LIBCPMT.LIB becomes the default library.

For a description of all the C run-time libraries, see the C Run-Time Libraries and C Run-Time Debug Libraries.


Make the Old iostream Library the Default

If you want to retain the old iostream library, include one or more of the old iostream header files in your code:

#include <fstream.h>
#include <iomanip.h>
#include <ios.h>
#include <iostream.h>
#include <istream.h>
#include <ostream.h>
#include <streamb.h>
#include <strstrea.h>

Do not use the new Standard C++ headers. You cannot mix calls to the old iostream and the new Standard C++ library. See C++ Library Overview for a list of the new Standard C++ header files. Many of the new Standard C++ iostream header files (fstream, iomanip, ios, iosfwd, iostream, istream, ostream, sstream, streambuf, and strstream) have names that are the same as or similar to the old iostream header files but without the .h extension. Be sure to include the .h extension if you want to use the old iostream library.

The old iostream library is contained in the following run-time library files: LIBCI.LIB, LIBCIMT.LIB, and MSVCIRT.LIB. The debug versions are contained in LIBCID.LIB, LIBCIMTD.LIB, and MSVCIRTD.LIB.

If you include the old iostream header files, the run-time library files that contain the old iostream library will be the default libraries. For example, if you choose Multithreaded in the Use run-time library drop-down list in the Code Generation category of the C/C++ tab in the Project Settings dialog box, and you have included an old iostream header file in your code, LIBCIMT.LIB becomes the default library.

For a description of all the C run-time libraries, seethe C Run-Time Libraries and C Run-Time Debug Libraries.


What Problems Can I Run into When Linking an Earlier Application?

The following topics cover difficulties you may run into with an earlier application and the new run-time libraries.

  • Differences in iostream implementation

  • Earlier projects built with no default libraries

  • C++ exception handling must be enabled for the Standard C++ library


Differences in iostream Implementation

The main difference between the Standard C++ library and previous run-time libraries is in the iostream library. Details of the iostream implementation have changed, and it may be necessary to rewrite parts of your code that use iostream if you want to link with the Standard C++ library.

You will have to remove any old iostream headers (fstream.h, iomanip.h, ios.h, iostream.h, istream.h, ostream.h, streamb.h, and strstrea.h) you have included in your code and add one or more of the new Standard C++ iostream headers (fstream, iomanip, ios, iosfwd, iostream, istream, ostream, sstream, streambuf, and strstream, all without the .h extension).

If your old application is very iostream intensive, you may choose not to link with the new Standard C++ library. In this case, leave the old iostream headers in your code and the old iostream library will automatically be linked. However, you cannot include any of the new Standard C++ library headers. You cannot mix calls to the old iostream library and the new Standard C++ library.

The following list describes behavior in the new Standard C++ iostream library that differs from behavior in the old iostream library.

In the new Standard C++ iostream library:

  • open functions do not take a third parameter (the protection parameter).

  • You cannot create streams from file handles.

  • You cannot open ofstream objects with the ios::out flag alone. The ios::out flag must be combined with another ios enumerator in a logical OR; for example, with ios::in or ios::app.

  • ios::good no longer returns a nonzero value after reaching the end-of-file because the eofbit state is set.

  • ios::setf( IFlags ) should not be used with a flag value of ios::dec, ios::oct, or ios::hex unless you know that none of the base flags are currently set. The formatted input/output functions and operators assume that only one base is set. Instead, use ios_base. For example, setf( ios_base::oct, ios_base::basefield ) clears all base information and sets the base to octal.

  • ios::unsetf returns void instead of the previous value.

  • istream::get( char& rch ) does not assign to rch if there is an error.

  • istream::get( char* pch, int nCount, char delim ) is different in three ways:
    • When nothing is read, failbit is set.

    • An eos is always stored after characters extracted (this happens regardless of the outcome).

    • A value of -1 for nCount is an error.
  • istream::seekg with an invalid parameter does not set failbit.

  • The return type streampos is a class with overloaded operators. In functions that return a streampos value (such as istream::tellg, ostream::tellp, strstreambuf::seekoff, and strstreambuf::seekpos), you should cast the return value to the type required: streamoff, fpos_t, or mbstate_t.

  • The first function parameter (falloc) in strstreambuf::strstreambuf( falloc, ffree ) takes a size_t argument, not a long.

In addition to the above changes, the following functions, constants, and enumerators that are elements of the old iostream library are not elements of the new iostream library:

  • attach member function of filebuf, fstream ifstream, and ofstream

  • fd member function of filebuf, fstream ifstream, and ofstream

  • filebuf::openprot

  • filebuf::setmode

  • ios::bitalloc

  • ios::nocreate

  • ios::noreplace

  • ios::sync_with_stdio

  • streambuf::out_waiting

  • streambuf::setbuf (use rdbuf()->pubsetbuf() for the same behavior)


Earlier Projects Built with No Default Libraries

You can build a project without default libraries by selecting the Ignore all default libraries option in the General category of the Link tab in the Project Settings dialog box (or with /NOD or /NODEFAULTLIB command-line switches). If your previous project was built with no default libraries and you want to make iostream calls, you must name one of the new Standard C++ run-time libraries (LIBCP.LIB, LIBCPMT.LIB, MSVCPRT.LIB, and so on) or one of the old iostream run-time libraries (LIBCI.LIB, LIBCIMT.LIB, MSVCIRT.LIB, and so on) in order to link with the proper library. Use the command line or the Object/library modules text box in the General category of the Link tab in Project Settings.

In previous Visual C++ versions (4.1 and earlier), the run-time library names were LIBC.LIB, LIBCMT.LIB, and MSVCRT.LIB. These libraries included the old iostream library. The old iostream library has now been removed from these libraries. If you do not choose to ignore default libraries and you include old iostream header files in your code, the old iostream run-time libraries (LIBCI.LIB, LIBCIMT.LIB, MSVCIRT.LIB, and so on) are linked by default. However, if you have chosen to ignore default libraries and have added one of the early run-time libraries by hand (on the command line or in the Object/library modules text box in the General category of the Link tab in Project Settings), your iostream calls will now break.


C++ Exception Handling Must be Enabled for the Standard C++ Library

Any file that uses the Standard C++ library must be compiled with C++ exception handling enabled. C++ exception handling is enabled by default, or can be enabled by selecting the Enable exception handling option in the C++ Language category of the C/C++ tab in the Project Settings dialog box, or by using the /GX compiler switch.


Upgrade Previous Visual C++ Enterprise Edition Projects

Home | Overview | How Do I | FAQ | Details

Feature Only in Enterprise Edition Projects with data sources are supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Projects built in previous Enterprise Edition versions of Visual C++ are converted automatically to the current version when you open them in Visual C++. Thus, to convert a project, open it, let Visual C++ do the conversion, and save the converted project. Save the converted project under a new name if you want to retain your old project for any reason.

Unlike versions prior to Visual C++ 5.0, data sources are no longer kept in a C++ project. Instead, data sources have their own project in Visual C++. You do not need a C++ project; your project can consist solely of data sources, and you can edit and debug the stored procedures within the data sources.

In Visual C++ Enterprise Edition, the data sources appear as a separate database project in FileView. You can switch to Data View by clicking the database project. When you open a project built in a previous version of Visual C++ Enterprise Edition, a database project is automatically created for the data sources. This project appears in FileView, along with the C++ project that once contained the data sources.


Port Applications to and from the Development Environment

Home | Overview | How Do I | FAQ | Details

If your C/C++ program is Visual C++ or ANSI standard C/C++, there is no problem porting it to the development environment. If you have a makefile created outside the development environment, your makefile will be wrapped and a project will be created with one file in it, your makefile. The project should still build and run from within the development environment.

If you do not have a makefile, open a new project workspace, select the compile and link settings you need, add your source C/C++ files to the project, and build the project.

You can also create a .MAK file from within the development environment that can be used to build the project from the command line. Note that in previous versions of Visual C++, a .MAK file that contained project settings and could also be used from the command-line was created automatically. Starting with Visual C++ 5.0, a .DSP file is created to hold the project settings. You can easily create a .MAK file to use from the command-line, but this file cannot be used later to open the project as a native project in the development environment. The .MAK file will be opened as a project that was not created in the development environment.

  • How do I port a project made with NMAKE to the development environment?

  • How do I port an external project made without NMAKE to the development environment?

  • How do I create a project in the development environment that can be built with NMAKE?

  • How do I create a project in the development environment that can be built with any tool?


Port a Project Made with NMAKE to the Development Environment

To open an external makefile in the development environment

  1. From the File menu, click Open Workspace.

    The Open Project Workspace dialog box appears.

  2. In the Files of type drop-down list, select All Files (*.*) to display all files.

  3. Select the drive and directory containing the previous makefile.

  4. Select the makefile from the list of files and click OK.

    –or–

    Double-click the filename in the list.

    If the makefile is not one that the development environment recognizes, a message box is displayed offering to create a new project workspace to wrap the external makefile.

  5. Click Yes.

    A Platforms dialog box appears. Select all the 32-bit platforms your application supports. You must select at least one platform.

  6. Click OK.

    A project is created with one file in it, your makefile, but the project will build and run within the development environment, assuming it is 32-bit compatible. However, to take advantage of wizards and integrated debugging features, it would be better for you to create a new project in the development environment, add your existing files to it, set the compile and link settings to match your old makefile, then build and save the up-to-date project.

You can also generate browser information for an external makefile. See Knowledge Base article Q102326. (Connect to http://www.microsoft.com/kb/ to access Knowledge Base articles. Choose Visual C++ in the Choose a Microsoft product or technology drop-down list. Enter the article number in the Enter a Search Phrase text box, then click Begin Search.)


Port an External Project Made Without NMAKE to the Development Environment

To open an external project in the development environment

  1. Follow the same steps you would to open a project made with NMAKE in the development environment.

  2. Once the project is open, click Settings from the Build menu.

  3. On the Project Settings dialog box, click the General tab.

  4. In the Build command line text box, replace the default NMAKE commands by typing in the command for your build tool.


Create a Project in the Development Environment That Can Be Built with NMAKE

There are two ways to export a makefile from the development environment. You can choose to export a makefile whenever you save a project, or export a makefile only for specific projects. Note that creating an export makefile increases project save time, and you should only do it when necessary.

The export makefile stores all the information required to build the project and can be used from the command line. The makefile specifies the same project build settings you set in the development environment. If you use NMAKE on the command line to build the project, the NMAKE syntax needed is given in the makefile as a comment that begins !MESSAGE NMAKE. For example, for a file test.mak the NMAKE syntax line is:

!MESSAGE NMAKE /f "test.mak" CFG="test - Win32 Debug"

To export an NMAKE makefile whenever you save a project

  1. From the Tools menu, click Options.

    The Options dialog box appears.

  2. On the Options dialog box, click the Build tab.

  3. Select the Always export makefile when saving project option.

  4. Click OK.

To export an NMAKE makefile for a particular project

  1. Open the project.

  2. From the Project menu, click Export Makefile.

    A .MAK file with the project name is immediately created and saved to the project directory.


Create a Project in the Development Environment That Can Be Built with Any Tool

To create a project in the development environment that can be built with any tool

  1. From the File menu, click New.

    The New dialog box appears.

  2. On the New dialog box, click the Projects tab.

  3. Select Makefile as the project type and enter the project name and location in the appropriate text boxes.

  4. Click OK.

    A message box appears that says you can specify a command line for your makefile in Project Settings and asks if you want to open Project Settings.

  5. Click Yes.

    The Project Settings dialog box opens with the Build command line text box selected.

  6. Type in the command line syntax for your build tool.

  7. Click OK.


Port from Other Languages

Home | Overview | How Do I | FAQ | Details

Rather than rewrite your Fortran or assembly language code, you should call your existing code from within Visual C++. Your functions and subroutines can reside in a separate module and be compiled on your native compiler. You can call into other-language modules from your C/C++ programs if you take into account differences in calling conventions and naming conventions among different languages. Often, these differences can be resolved by declaring other-language functions in C/C++ with keywords, such as _stdcall and extern "C". See Mixed-Language Programming Topics for more information.


Port to and from Non-Intel Platforms

Home | Overview | How Do I | FAQ | Details

Visual C++ and its cross-development add-ons allow you to port your applications from Intel-based Visual C/C++ to RISC platforms, or from RISC-based Visual C++ applications to Intel platforms.

  • Port non-Visual C++ applications from different platforms to Visual C++

  • Port Visual C++ applications between Intel-based and RISC platforms (Alpha or PowerPC)

  • Port from UNIX to Win32


Port Non-Visual C++ Applications from Different Platforms to Visual C++

Before you port your application, decide what kind of Visual C++ application you want to port to:

To port non-Visual C++ applications to Visual C++

  1. From the File menu, click New.

    The New dialog box opens.

  2. Select the Projects tab.

  3. Select the kind of application you want to create:
    • Choose Application to create an EXE

    • Choose Dynamic Link Library to create a DLL

    • Choose Static Library to create a LIB

    • Choose Console Application to create an EXE with no Graphical User Interface (GUI)
  4. Enter a project name and location in the appropriate text boxes.

  5. Click OK.

    An empty project is created and opened.

  6. From the Project menu, click Add to Project and then Files.

    The Insert Files into Project dialog box appears.

  7. Select the drive and directory containing the project files.

  8. Select the files you want to add from the list. (You can select more than one by holding down the SHIFT key while selecting.)

  9. Click OK.

  10. Examine and/or modify your new project settings by clicking Settings from the Build menu.

  11. Build the project.


Port Visual C++ Applications Between Intel-Based and RISC Platforms (Alpha or PowerPC)

Visual C++ for Alpha and PowerPC is designed to be portable between both RISC platforms and Intel platforms. MFC is designed to make C++ code universal on all these platforms, and applications should port easily.

If you have the RISC cross-development package installed, you can convert Intel-based projects to RISC-based projects and vice versa automatically. You can also open any project in the development environment on any platform and change the build settings, but you cannot build a project created on one platform in the development environment on another platform without converting it first.

  • Convert Visual C++ RISC projects in Intel-based Visual C++

  • Convert Intel-based Visual C++ projects in RISC Visual C++

  • RISC Bit Alignment

Convert Visual C++ RISC Projects in Intel-Based Visual C++

To convert RISC projects to Intel-based projects

  1. On your Intel-based computer, click Open Workspace from the File menu.

    The Open Project Workspace dialog box opens.

  2. Select your RISC project and click Open.

  3. From the Build menu, click Configurations.

    The Configurations dialog box appears. Notice that the RISC configuration projects are listed, but are unavailable.

  4. Click Add.

    The Add Project Configuration dialog box appears.

    This will be the name of your Intel version of the project.

  5. In the Platforms drop-down list, select Win32.

  6. Give a name for the new configuration in the Configuration edit box, such as Debug(x86).

  7. Click OK.

    An Intel-based project with the same build settings as your RISC-based project is automatically created.

Convert Intel-Based Visual C++ Projects in RISC Visual C++

To convert Intel-based projects to RISC projects

  1. On your RISC computer, click Open Workspace from the File menu.

    The Open Project Workspace dialog box opens.

  2. Select your Intel project and click Open.

  3. From the Build menu, click Configurations.

    The Configurations dialog box appears. Notice that the Intel-based configuration projects are listed, but are unavailable.

  4. Click Add.

    The Add Project Configuration dialog box appears.

  5. In the Platforms drop-down list, select your RISC platform (Alpha or PowerPC). Only those platforms for which you have a cross-development package appear in the Platforms list.

  6. Give a name for the new configuration in the Configuration edit box, such as Debug(x86).

  7. Click OK.

    A RISC-based project with the same build settings as your Intel-based project is automatically created.

RISC Bit Alignment

RISC platforms expect data to be laid out in 32-bit parcels. If you try to extract data from the middle of a 32-bit parcel, you get an alignment fault. Handle this by:

  1. Making sure all data lines up on 32-bit addresses.

  2. Adding the keyword UNALIGNED in front of pointers.

See Knowledge Base article Q92762. (Connect to http://www.microsoft.com/kb/ to access Knowledge Base articles. Choose Visual C++ in the Choose a Microsoft product or technology drop-down list. Enter the article number in the Enter a Search Phrase text box, then click Begin Search.)


Port from UNIX to Win32

When migrating applications from UNIX to Windows, there are several options:

  • Running UNIX applications on Windows NT using the POSIX subsystem

  • Using UNIX libraries to port applications from UNIX to Win32

  • Porting applications from UNIX to Win32 natively

The first option UNIX programmers look at is the Windows NT POSIX subsystem. However, it only supports POSIX 1003.1, which was the only POSIX version standardized when Windows NT was created. Since then, there has been little demand for extending this subsystem, because most applications have been converted to Win32. The 1003.1 system is of limited interest for fully featured applications, because it does not include many capabilities (such as those in 1003.2, network support, and so on). Full featured applications run under the Windows NT POSIX subsystem do not have access to Windows NT features available to Win32 applications, such as memory-mapped files, networking, and graphics. Applications such as VI, LS, and GREP are the main targets for the Windows NT POSIX subsystem.

The second option UNIX programmers normally consider is using third-party UNIX-like libraries to let their UNIX code compile as a Win32 executable. Several commercial (and at least one public domain) libraries do this. This is an option for some applications. The advantage of these porting libraries is that they minimize the initial porting effort. The main disadvantage, for a competitive software product, is that a native Win32 port of an application will generally be faster and will inevitably have more functionality. It can be awkward for the application to step outside of its UNIX shell if it needs to make Win32 calls to get more power from Windows NT.

The third option is porting UNIX applications directly to Win32. Using ANSI C/C++ libraries, and commercial C compiler libraries, many of the traditional system calls relied on by UNIX applications are available in Win32 applications.

The output model of stdio-based applications does not need to be changed, since the Win32 console APIs mimic the stdio model, and versions of cursors exist that use the Win32 console APIs.

Berkeley socket-based applications need very few changes to work as Win32 applications. The Windows Sockets interface was designed for portability with BSD sockets, with minimal changes that are noted in the introductory sections of the WinSock specification. See Deviation from Berkeley Sockets.

Windows NT supports DCE-compliant RPC, so RPC-based applications are easily usable. See the Introduction to Run-Time RPC Functions.

One of the largest areas of difference is in the process model. UNIX has fork; Win32 does not. Depending on the use of fork and the code base, Win32 has two APIs that can be used: CreateProcess and CreateThread. A UNIX application that forks multiple copies of itself can be reworked in Win32 to have either multiple processes or a single process with multiple threads. If multiple processes are used, there are multiple methods of IPC that can be used to communicate between the processes (and perhaps to update the code and data of the new process to be like the parent, if the functionality that fork provides is needed). See Creating a New Interprocess (IPC) Message Class.

Windows and UNIX graphical models are very different. UNIX uses the X Window System GUI, while Windows uses GDI. Though similar in concept, there is no simple mapping of the X API to the GDI API. However, OpenGL support is available for migrating UNIX OpenGL-based applications. And there are X clients and X servers for Windows. See Graphics Device Interface for information on GDI.

Basic UNIX applications, including many CGI applications, should port easily to Visual C++ running on Windows NT. Functions like open, fopen, read, write and others are available in the Visual C++ run-time library. Also, there is a one-to-one mapping between C UNIX APIs and Win32 APIs: open to CreateFile, read to ReadFile, write to WriteFile, ioctl to DeviceIOControl, close to CloseFile, and so on.


Port Between 16-Bit and 32-Bit ActiveX Controls

Home | Overview | How Do I | FAQ | Details

When porting between 16-bit and 32-bit controls, you must work around the following constraints:

  • You can use 16-bit controls only in 16-bit containers and 32-bit controls only in 32-bit containers.

  • You cannot port 16-bit controls to 32-bit controls.

To write a 16-bit ActiveX control, you must use Visual C++ 1.x and the 16-bit version of the Microsoft OLE Control Development Kit (CDK). These 16-bit versions of Visual C++ and the CDK are shipped with current and recent 32-bit versions of Visual C++, including version 5.x, on a separate CD-ROM disc. Install both from that disc and look at the CDK documentation to get started on a 16-bit control.

The best approach for creating both 16-bit and 32-bit versions of your ActiveX control is to port the 32-bit version to a 16-bit implementation. For the issues involved, see Adam Denning's book ActiveX Controls Inside Out Second Edition (Microsoft Press, 1996).

Note Some aspects of ActiveX controls and control containment available in Visual C++ 4.0 and later are not available in 16-bit versions of Visual C++. Future ActiveX control improvements, such as OLE Database and OLE Transactions, will never have 16-bit implementations.


Port Visual Basic Controls and Existing CDK Projects

Home | Overview | How Do I | FAQ | Details

You can use Visual Basic controls in your Visual C++ projects, and vice versa. To port Visual Basic controls to a Visual C++ project, you must create a framework in ControlWizard, then manually port the code for the Visual Basic control to the ActiveX control framework. See ActiveX Controls: VBX Control Migration for details.

As of Visual C++ 4.0, the Microsoft OLE Control Development Kit (CDK) became fully integrated with the Microsoft Foundation Class Library (MFC).

  • To port existing CDK projects to Visual C++, see ActiveX Controls: Converting a CDK Project to a Visual C++ Project.

  • To add a new ActiveX control to an existing CDK project, see ActiveX Controls: Adding an ActiveX Control to an Existing CDK Project.


Port ActiveX Controls to Other Applications

Home | Overview | How Do I | FAQ | Details

You can use ActiveX controls developed in Visual C++ in other applications, as long as they support ActiveX control containment. A number of applications, including the following from Microsoft, support ActiveX control containment:

  • Internet Explorer 3.x

  • Internet Explorer 4.x

  • Visual Basic 4.x

  • Visual Basic 5.x

  • Visual Basic 6.0

  • Visual C++ 4.x

  • Visual C++ 5.0

  • Visual C++ 6.0

  • Access 95

  • Excel '97

  • Word '97

  • Access '97

  • Front Page '97

  • Power Point '97

  • Visual InterDev '97

The following are non-Microsoft applications that support ActiveX control containment:

  • PowerBuilder

  • Delphi

  • C++ Builder

  • NCompass Plug-in for Netscape Navigator

Note Visual FoxPro did not fully meet the containment guidelines in version 3.0 but will in the next version.


Upgrade to an Active Document Server

Home | Overview | How Do I | FAQ | Details

If your application was created with a version of Visual C++ prior to version 4.2 and is already an in-place server, you can add Active document support by following the procedure below. If your application is not already an in-place server, you must first add this support as described in the tutorial, Creating an OLE Server, and then follow the steps described.

To add Active document support to an existing server

  1. In your project’s stdafx.h, add the following line of code to include document object support:
    #include <afxdocob.h>
  2. In your CWinApp-derived class, change the parameter to UpdateRegistry from OAT_INPLACE_SERVER to OAT_DOC_OBJECT_SERVER:
    m_server.UpdateRegistry(OAT_DOC_OBJECT_SERVER);
  3. In your in-place frame class, change its derived class from COleIPFrameWnd to COleDocIPFrameWnd. You will need to make changes in both the .H file and in the .CPP file.
    • In the header file, derive your in-place frame class from COleDocIPFrameWnd:
      class CInPlaceFrame : public COleDocIPFrameWnd
    • In the .CPP file, search for COleIPFrameWnd and replace each occurrence with COleDocIPFrameWnd.
  4. In your item class, change its derived class to CDocObjectServerItem:
    class CMyItem : public CDocObjectServerItem

    In the .CPP file, search for COleServerItem and replace each occurrence with CDocObjectServerItem.

  5. In your document class header file, insert the following line to add a parse map to route OLE menu commands such as Print between the container and your server. (Add the line in the message map function section, after the line DECLARE_MESSAGE_MAP.)
    DECLARE_OLECMD_MAP()

    In the document class .CPP file, use the BEGIN_OLECMD_MAP macro, add macro entries for each of your message-handler functions, and add the END_OLECMD_MAP macro. An AppWizard-generated application contains the following map:

    BEGIN_OLECMD_MAP(CMyDoc, COleServerDoc)
ON_OLECMD_PAGESETUP()
ON_OLECMD_PRINT()
END_OLECMD_MAP()

    This OLE command map routes the Print and Page Setup commands to their handler functions using standard IDs ID_FILE_PRINT and ID_FILE_PAGE_SETUP. You must have command maps for these functions in your code, for example:

    ON_COMMAND (ID_FILE_PRINT, OnFilePrint)
  6. In your document class header file, add a function declaration in the public section of your document class:
    CDocObjectServer* GetDocObjectServer(LPOLEDOCUMENTSITE pSite);

    In your document class header file, implement the function as follows:

    CDocObjectServer* CMyDoc::GetDocObjectServer(LPOLEDOCUMENTSITE pSite)
{
return new CDocObjectServer(this, pSite);
}


Upgrade Previous Versions of WinHelp

Home | Overview | How Do I | FAQ | Details

To upgrade previous versions of WinHelp

  1. Start the Help Workshop by running HCW.EXE.

    This file is installed in \Program Files\Microsoft Visual Studio\VC98\bin in a default product installation.

  2. In the Help Workshop, open your previous .HPJ file.

    Help Workshop automatically adds entries to the file.

  3. Use Help Workshop to make any modifications to your previous Help file and then save the file.

    Help Workshop saves your file in the new format.

For more information, see online help in the file HCW.HLP, installed by default in the \Program Files\Microsoft Visual Studio\VC98\bin directory. You can open the file by double-clicking it, or view it by choosing Help from within Help Workshop.


Write Code That Works on the Largest Number of Platforms

Home | Overview | How Do I | FAQ | Details

For code that is most universal among the following platforms, use MFC.

  • Write portable code for Windows

  • Write portable code for UNIX

If you cannot use MFC, you can make your C-based applications work on both 16-bit and 32-bit Windows by using message crackers. Note that message crackers work only on Windows operating systems.


Write Portable Code for Windows

MFC is an application framework designed for rapid Windows development. Visual C++ for Intel x86, Alpha, and PowerPC are all Windows NT-based. They are designed to be portable among each other. MFC's job is to make C++ code universal on these platforms by wrapping the system-dependent code, such as messages, and your applications should port easily among the platforms. In most cases, a Visual C++ application created in the development environment on one of these platforms can be opened in the development environment on another platform and the conversion is done automatically. See Porting to and from Non-Intel Platforms.


Write Portable Code for UNIX

If you have the UNIX version of MFC on your UNIX system, your Visual C++ applications should port with little difficulty.

If you do not have MFC on your UNIX system, you can still port your Visual C++ applications to UNIX using the Standard C++ libraries and the Visual C++ compiler libraries. Many UNIX functions, such as open, fopen, read, and write, are available in the Visual C++ run-time library. Also, there is a one-to-one mapping of these UNIX APIs to Win32 APIs: open to CreateFile, read to ReadFile, write to WriteFile, ioctl to DeviceIOControl, close to CloseFile, and so on. Many of the traditional system calls relied on by UNIX applications are available as Win32 APIs. See Port from UNIX to Win32 for a discussion of compatibility issues, such as multithreading.

You need to consider UNIX when writing your C/C++ code; for example, UNIX filenames are case-sensitive. See UNIX for compatibility guidelines when porting Visual C++ to UNIX.


Write Code That Works in the Largest Number of C Compilers

Home | Overview | How Do I | FAQ | Details

For code that is most universal among C compilers, write strictly ANSI C and ANSI C++ code.

To write strict ANSI C/C++ code

  1. Do not use the MFC library. Call Win32 APIs directly.

  2. Disable Microsoft extensions.

  3. Use the iostream library from the ANSI Standard C++ library.

  4. Use the Standard template library from the ANSI Standard C++ library.


Platform Portability Without MFC

If you cannot use MFC, you can make your C-based applications work on both 16-bit and 32-bit Windows by using message crackers. Note that message crackers work only on Windows operating systems.


Disable Microsoft Extensions to C++

Disable language extensions if you plan to port your program to other C compilers. If you disable extensions, the Visual C++ compiler treats extended keywords as simple identifiers, disables the other Microsoft extensions, and automatically defines the __STDC__ predefined macro for C programs. See Microsoft Extensions to C for a list of Microsoft-specific extensions. See the /Za, /Ze (Disable Language Extensions) compiler option topic for details on disabling extensions.

To disable Microsoft extensions to C++

  • Select the Disable language extensions option in the Customize category of the C/C++ tab in the Project Settings dialog box.

    – or –

    Use the /Za command-line option.

In both methods, the compiler flags language constructs not compatible with ANSI C++ as errors.


Write Code That Is Easy to Internationalize

Home | Overview | How Do I | FAQ | Details

To write code that is easy to internationalize

  1. Write code that can be built as either Unicode or MBCS (multibyte character set).

    If you must choose one, use MBCS for strings. MBCS works for all 32-bit Windows, while Unicode is not supported on Windows 95.

  2. Do not hard code strings. Instead make them STRINGTABLE resources.

    You will not have to recompile and build your sources when the language in the strings changes.

See International Programming Topics for details.


Frequently Asked Questions: Porting and Upgrading

Home | Overview | How Do I | Details

  • How do I delete an older version of Visual C++?

  • How do I transfer a project from a previous version of Visual C++?

  • How do I convert an old makefile to Visual C++?

  • How do I open a project built in Visual C++ 2.x?

  • How do I open a project built in Visual C++ 4.x?

  • What are the differences in MFC versions?

  • How do I port a UNIX application?

  • What are the major changes from Visual C++ 2.0 to 4.0?

  • What are the major changes from Visual C++ 4.0 to 4.2?

  • What are the major changes from Visual C++ 4.2 to 5.0?

  • What are the major changes from Visual C++ 5.0 to 6.0?

  • How do I compile and link C code, not C++?

  • What happened to the CDK?

  • Can I convert my Visual Basic custom control (VBX) to an ActiveX control?


How do I delete an older version of Visual C++?

For Visual C++ versions 4.0 and later, open the program group and click the Uninstall icon.

For earlier versions, move your project files to a safe directory, delete the Visual C++ directories, then use Regedit or a tool like it to delete the Visual C++ folder from the registry; for example, delete the folder HKEY_CURRENT_USER\Software\Microsoft\Developer.

Warning Be very careful when deleting folders from your registry. Serious damage can result to your computer configuration if you delete the wrong one.


How do I transfer a project from a previous version of Visual C++?

See Upgrade Previous 32-Bit Versions of Visual C++ and Upgrade Previous 16-Bit Versions of Visual C++.


How do I convert an old makefile to Visual C++?

See:

  • How do I port a project made with NMAKE to the Visual C++ environment?

  • How can I port an external project made without NMAKE to the Visual C++ environment?


How do I open a project built in Visual C++ 2.x?

See Upgrade Previous 32-Bit Versions of Visual C++.


How do I open a project built in Visual C++ 4.x?

See Upgrade Previous 32-Bit Versions of Visual C++.


What are the differences in MFC versions?

See Changes in MFC Versions.


How do I port a UNIX application?

See Port from Unix To Win32.


What are the major changes from Visual C++ 2.0 to 4.0?

See Changes from MFC Versions 3.x for a description of changes in the Microsoft Foundation Class Library.

The major changes to Visual C++ since the 2.0 version are:

Feature changes:

  • Component Gallery with new prebuilt objects including ActiveX controls.

  • Build your own ActiveX controls.

  • Customizable AppWizard.

  • Integrated source-code control.

Development Environment changes:

  • ClassView.

  • WizardBar.

  • Enhanced text editor (including BRIEF and Epsilon emulation) and resource editor.

  • Support for importing Visual Basic forms lets you reuse forms and migrate easily.

Build system changes:

  • Incremental compiler compiles only the functions that have changed.

  • Incremental linker relinks only modules that have changed.

  • Minimal rebuild builds only the files that need to be built.

Database support changes:

  • MFC DAO classes that use the Microsoft Jet database engine, version 3.0 or later.

  • ODBC support through MFC ODBC classes and high-performance 32-bit ODBC drivers.

  • Visual C++ wizard support for both MFC DAO and MFC ODBC classes.


What are the major changes from Visual C++ 4.0 to 4.2?

In addition to performance improvements, Visual C++ 4.1 and Visual C++ 4.2 incorporate the following new features:

  • Internet server classes

    MFC wraps the new Win32 Internet (WinInet) and COM/ActiveX control technology to make Internet programming easier. See Changes from MFC Versions 3.x for a description of changes in the Microsoft Foundation Class Library.

  • AppWizard for creating Internet applications

    The ISAPI Extension Wizard creates Internet server extensions and filters. Internet server extensions and filters are DLLs based on the new Internet Server API (ISAPI) MFC classes.

    To access the ISAPI Extension Wizard, click the New command from the File menu and then click the Projects tab in the New dialog box.

  • Additions to Visual C++ wizards

    Starting with version 4.2, Visual C++ includes several changes to AppWizard (supports creating an Active document server), ActiveX ControlWizard (supports new ActiveX control options, such as windowless controls), and ClassWizard (supports asynchronous monikers) to make COM programming easier.

  • Standard C++ Library

  • ODBC feature enhancements

    Starting with version 4.2, MFC provides multithreading support for the ODBC classes. The MFC ODBC classes no longer use asynchronous processing. Data access operations are now synchronous. Class CDatabase provides improved support for transactions. Class CRecordset offers support for bookmarks and provides support for bulk row fetching.

  • Remote Data Accessibility and Data Binding

    Starting with version 4.2, Visual C++ includes controls that you can bind to local or remote data sources. These controls, contained in the Component Gallery, are:

    • MSDataCombo Control

    • MSDataList Control

    • Apex Data Bound Grid Control

    • Microsoft Masked Edit Control

    • Calendar Control

    You can bind these controls to the RemoteData Control, which is also found in the Component Gallery.

  • Changes to the Visual C++ Image Editor

    The Image Editor can now read and write both GIF and JPEG file formats.

  • Small block heap manager

    For performance reasons, the C run-time library's memory-management routines for Windows NT and Windows 95 incorporate a special heap manager for small allocations.

  • Win32s advisory

    Win32s development is not supported in Visual C++ versions 4.2 and later.

  • Solution to the name-length limitation

    Starting with version 4.2, Visual C++ includes two warning messages that provide a workaround to the 255-character limit for symbol names in the debugger.

  • World Wide Web access within the development environment

    Starting with Visual C++ 4.1, you can access World Wide Web sites from within the development environment. Click the Microsoft on the Web command from the Help menu. This offers a list of Microsoft Web sites for Visual C++ developer support.


What are the major changes from Visual C++ 4.2 to 5.0?

Microsoft Visual C++ version 5.0 includes the following new features and tools:

C++ Language

  • New C++ keywords include bool, explicit, false, mutable, true, and typename for better C++ conformance.

  • You can now use __declspec to declare whether the specified storage-class attribute applies to a type or to a variable of a type.

Compiler, Linker, and NMAKE

  • Compiler support for COM simplifies developing C++ clients that use COM objects. Included are samples that demonstrate using native compiler COM support
    • ACDUAL illustrates Dual interface support for MFC applications.

    • INPROC illustrates in-process Automation server.

    • MFCCALC illustrates Automation server that implements a simple calculator.

    • COMEXCEL illustrates stand-alone Automation client that creates a new Microsoft Excel spreadsheet and generates a pie chart.

    • COMIDE illustrates stand-alone Automation client that automates Microsoft Developer Studio.

    • COMMAIL illustrates stand-alone Automation client that automates MAPI for Microsoft Exchange 4.0.

    • COMMMAP illustrates the use of different COM interface map-entry macros.

    • LABRADOR illustrates the use of ATL to implement an EXE server with no user interface.

    • FREETHRD illustrates a multithreaded client and free-threaded server with compiler COM support.

    • ALLINONE illustrates the use of MAC, STL, ATL and COM.
  • Compiling with /O1 provides a 5% to 10% size reduction over Visual C++ version 4.2.

  • To create smaller release executables, the linker uses the /FIXED option. Because the profiler requires relocation information it must use either the linker's /PROFILE or /FIXED:NO option. This also applies to other post-link tools such as BoundsChecker or Purify.

  • The new /EH compiler options give you greater control of C++ exception handling. C++ synchronous exception handling (/EHs), which allows the compiler to generate smaller code, is the new default C++ exception-handling model for Visual C++.

  • The actions of the /G3, /G4, /G5, /G6, and /GB compiler options, which control which processor your code is optimized for, have changed.

  • The /GX compiler option now maps to /EHsc.

  • The /PDBTYPE linker option allows you to specify which program database (PDB) will contain debug type information. This option can save disk space and speed linking.

  • NMAKE supports batch-mode rules.

AppWizard

  • AppWizard will now automate the dialog class in a dialog-based application. Simply create a dialog-based application and select support for Automation (formerly OLE Automation). The result is a dialog-based application with basic Automation as was done in earlier versions of AppWizard. In addition, the dialog class is also exposed through Automation, via a separate proxy class. You can add methods and properties that expose elements of the dialog.

  • Custom AppWizards now have the ability to modify the build settings of the project they create. For example, you can adjust the compiler, linker, and browser settings and /or add custom build steps that execute after the target is built.

MFC

  • Asynchronous (URL) monikers enable your application, typically for the Internet, to download files and control properties asynchronously, thus freeing system resources for other processes while the tasks are completed.

  • Active documents can be displayed either in the entire client window of a Web browser, such as Internet Explorer 3.0, or in an OLE container — such as the Microsoft Office Binder — that supports ActiveX documents.

  • Win32 Internet API (WinInet) makes the Internet an integral part of any application and simplifies access to the Internet services FTP, HTTP, and gopher.

  • MFC now supports DAO 3.5.

  • Support for ODBC 3.0 provides several important changes to the MFC ODBC classes.

  • The return types of the COleDateTime member functions SetDate, SetDateTime, and SetTime have been changed from BOOL to int. Each of these member functions returns 0 if the COleDateTime object was set successfully; otherwise, 1. This return value is based on the DateTimeStatus enumerated type.

  • A new sample program called IMAGE. This program generates an ActiveX control that is capable of downloading data asynchronously.

Active Template Library (ATL) 2.1

For information on features that have been added or changed since ATL version 1.1, see What's New in ATL 2.1.

C Runtime Library

  • The _itoa, _i64toa, and _ui64toa functions convert digits to a null-terminated character string and store the result in a string. The _itow, _i64tow, and _ui64tow functions are wide-character versions of _itoa, _i64toa, and _ui64toa respectively

  • These common floating-point transcendental functions have performance improvements that average 35% with no significant loss of accuracy: pow, sqrt, log, log10, sin, cos, tan, asin, acos, atan.

  • The performance of the memmove and memcpy functions is significantly improved.

ANSI Standard C++ Library

These libraries now conform to the ANSI C++ (X3J16) Working Paper dated September 24, 1996, ANSI Doc No. X3J16/96-0178 WG21/N0996. This paper was produced by the Stockholm meeting of July 1996.

OLE DB

OLE DB is a set of OLE interfaces that provide applications with uniform access to data stored in diverse information sources. These interfaces support the amount of database functionality appropriate to the data source, enabling it to share its data.

The OLE DB Software Development Kit (SDK) is a set of software components, tools, and documentation designed to help you in developing OLE DB consumers and providers for the Windows 95 and Windows NT 4.0 operating systems.

ERRLOOK - Look Up System Error Messages

This utility enables you look up system error messages, including OLE HRESULTs, by their value. You can drag and drop error values from the debugger, or copy and paste, or type them in. You can enter values in hexadecimal or decimal format. The error message text that ERRLOOK returns can be copied and pasted to other applications. ERRLOOK has context-sensitive help that describes how to use the utility.

New Sample Programs

Visual C++ 5.0 ships with several new samples. For more information, see the Samples home page.

Features Only in the Enterprise Edition

These features are supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Microsoft Visual C++ version 5.0 Enterprise Edition provides the following new features and tools for developing and validating enterprise applications:

  • Microsoft Transaction Server for building transaction-based applications.

  • Visual Database Tools for graphically designing databases and SQL queries.

  • Better performance while debugging a database connection: this process now runs much faster than before.

  • Extended SQL data type support so you can now change the values of local variables for all SQL data types (except text and image). This includes changing the data types money and datetime. You can change the values of local variables to and from the NULL value. You can also view all SQL types including text and image.

Features New to the Developer Studio Shell

Note In version 5.0, the shell for Visual C++ was called Developer Studio.

Developer Studio includes the following new features:

  • Automation and Macros

    Use Visual Basic Script to automate routine or repetitive tasks. Macro recording allows quick authoring. You can manipulate Developer Studio and its components as objects. This means you can automate tasks that include opening, editing, or closing documents, or sizing windows. You can also create integrated add-ins using Developer Studio's object model.

  • ClassView

    You can create new classes using MFC, ATL, or your own classes. You can use folders to organize classes the way you want in ClassView.

    ClassView also now provides the ability to view and edit interfaces for COM objects implemented in MFC or ATL.

  • Customizable toolbars and menus

    You can customize toolbars and menus with greater flexibility, to fit the way you work. For example, you can:

    • Create a new toolbar or menu.

    • Customize an existing toolbar or menu.

    • Add or remove menu commands or toolbar buttons.

    • Add a menu to a toolbar.

    • Move a menu command to become a toolbar button.

    • Move a toolbar button to become a menu command.

    • Copy a menu or toolbar button on more than one toolbar, so it remains available when some toolbars are hidden.
  • Debugger

    You can connect to running applications and debug them, and use macro language support to automate the debugger.

  • Project Workspaces and Files

    Workspace files now have the extension .dsw (formerly .mdp). Project files now have the extension .dsp (formerly .mak).

    Build files have been separated into two types: internal (.dsp) and external (.mak). Internal build files are created when you create a new project within the development environment or when you convert a project from a previous version. Internal build files are not compatible with NMAKE. You can create an external build file, compatible with NMAKE, by clicking Export Makefile on the Project menu.

    The process for creating new workspaces and files is easier: you use the same dialog box to create a workspace, a project, or a file, and you can create a new item and insert it into a project or workspace at the same time.

    Your projects can contain active documents, such as spreadsheets and Word document files, and you can edit them without leaving the development environment.

    The file workspacename.dsw, created when you create a workspace, is a new extension. The workspace file no longer includes data specific to your local computer. Now you can:

    • Add the workspace file to a source control project.

    • Copy a workspace from another computer or a network directory and open the workspace copy directly, without creating a new workspace file for your local computer.
  • Resource Editors

    Use the WizardBar with dialog boxes to hook up code to the visual elements of your program.

    The Accelerator, Binary, Dialog, and String editors support searching with the Find command to locate accelerator keys, ASCII strings, hexadecimal bytes, control IDs or labels, and specific strings.

    If you are working on accelerators, dialog boxes, menus, or strings, and you need to make the same change to multiple items, you can do so by selecting all of the items you want to change and then clicking Properties on the View menu. When you have multiple items selected, the Properties command displays a Multiple Selection property page. The changes you make on this page apply to each item, and if you need to undo a change, you need to choose the Undo command only once.

  • Text Editor

    The editor can color extensionless header files with the proper syntax coloring. For more information, see Setting Syntax Coloring.

    If you want to distinguish clearly between the control and text areas of a source window, customize the color of the selection margin. This is especially useful when editing source files without much vertical alignment of elements, such as HTML.

    The Find in Files command supports two separate output panes. This feature allows you to retain the output from a previous search.

  • What's This Help

    What's This Help is contextual, specific Help for controls in dialog boxes and windows. To use this form of Help, click the What's This button, which appears as a ? in the upper-right corner of a dialog box or window. The cursor changes to a question mark and you can then click any control on a dialog box or window to display a short help topic about the control.

  • Wizards

    There are new wizards that you can use to create files, controls, and new types of projects.


What are the major changes from Visual C++ 5.0 to 6.0?

See What's New for Visual C++ Version 6.0.


How do I compile and link C code, not C++?

Give your files the .C extension, for example mysource.C. The Visual C++ compiler automatically assumes that files with the .C extension are C files and not C++ files, and rejects C++ syntax and keywords (such as public, private, and class).

C++ files use the .CPP extension.


What Happened to the CDK?

As of Visual C++ 4.0, the Microsoft OLE Control Development Kit (CDK) became fully integrated with the Microsoft Foundation Class Library (MFC). For 32-bit ActiveX control development, this is the way to go. For 16-bit ActiveX controls, you must still use a 16-bit version of both Visual C++ and the CDK. For more information, see:

  • ActiveX Controls: Converting a CDK Project to a Visual C++ Project.

  • ActiveX Controls: Adding an ActiveX Control to an Existing CDK Project.

The first version of the CDK shipped with Visual C++ 2.0. Both 16-bit and 32-bit versions of the CDK were included.

Version 2.1 of Visual C++ included version 1.1 of the CDK, both 16-bit and 32-bit.


Can I Convert My Visual Basic Custom Control (VBX) to an ActiveX Control?

Yes, you can. See ActiveX Controls: VBX Control Migration.


Details: Porting and Upgrading

Home | Overview | How Do I | FAQ

Read these in-depth articles for a full discussion of porting and upgrading issues.

  • Porting 16-Bit Code to 32-Bit Windows

  • Porting 16-Bit MFC to 32-Bit MFC

  • Changes in MFC Versions

  • Porting and Upgrading OCXs and VBXs


Porting 16-Bit Code to 32-Bit Windows

Home | Overview | How Do I | FAQ | Details

The following topics cover the differences between 32-bit and 16-bit code in detail and discuss the adaptations you need to make to your 16-bit code.

  • Overview of 32-Bit Programming

  • Porting Applications

  • Revising the Window Procedure Declaration

  • Removing Near and Far Type Declarations

  • Using Proper Data Types

  • Handling 32-Bit Messages

  • Extracting Data from Messages with Portable Code

  • Adjusting Calls to API Functions

  • Revising the WinMain Function

  • Special Considerations for Advanced Applications


Overview of 32-Bit Programming

The 32-bit API was designed to minimize the impact on existing code so that 16-bit applications could be adapted as easily as possible. However, some changes were mandated by the larger address space. Pointers are all 32 bits wide and no longer near or far, and your code cannot make assumptions based on segmented memory.

Items which have increased to 32 bits include:

  • Window handles

  • Handles to other objects, such as pens, brushes, and menus

  • Graphics coordinates

These size differences are generally resolved in WINDOWS.H or by the C language, but some changes to source code are necessary. Because the different sizes can change the way information is packed in some message parameters, you must rewrite code that handles these messages. The larger size of graphics coordinates also affects a number of function calls.

Some source code changes are required because Win32 uses higher-level mechanisms for certain operations, such as MS-DOS calls. With these mechanisms, the 32-bit API is adaptable to many platforms, and it supports powerful new features such as multiple threads of execution.

Although Windows 3.x and Win32 were designed to be as compatible as possible, you may need to carefully review large amounts of source code. Where do you start? The top-down approach is recommended:

  1. Compile the application for 32 bits, and note the compiler-generated errors.

  2. Replace complex procedures that are difficult to port, and procedures written in assembly language, with stub procedures (which do nothing except return).

  3. Fix errors in the main portion of the application, using the techniques described in this chapter.

  4. Individually fill each stub procedure with portable code after the main portion of the application compiles and runs correctly.


Porting Applications

The following sections describe general areas of code you need to modify when porting a 16-bit application to Win32. These areas include the following:

  • Window procedure declarations

  • Near and far type declarations

  • Data types

  • Messages

  • Calls to API functions

  • WinMain function

If your application uses advanced techniques, such as manipulating the WIN.INI file, focus, and mouse capture, you may need to consult the section Special Considerations for Advanced Applications.


Revising the Window Procedure Declaration

To port a Windows 3.x application, you must revise the declaration of the window procedure. The following is a declaration of a window procedure for a Windows 3.x application.

LONG FAR PASCAL MainWndProc(  HWND hWnd,
    unsigned message,
    WORD wParam,
    LONG lParam)

To revise the declaration for Win32, replace the data types used in Windows 3.x as shown in the table. The following code can be compiled as a 32-bit application, but it can still be used to compile 16-bit applications as before:

LRESULT CALLBACK MainWndProc(  HWND hWnd,
    UINT message,
    WPARAM wParam,
    LPARAM lParam)

This table summarizes the changes to the declaration noted in the previous example.

Changes to the Window Procedure Declaration

Windows 3.x | Win32 (portable code) | Reason for changing
FAR PASCAL | CALLBACK | CALLBACK is guaranteed to use whatever calling convention is appropriate for windows and dialog procedures.
unsigned | UINT | Meaning is the same, but UINT guarantees portability for future platforms.
WORD | WPARAM | WORD is always 16 bits. The WPARAM type grows to 32 bits.
LONG | LPARAM | Meaning is the same (32 bits), but LPARAM guarantees portability for future platforms.

A significant difference between the Windows 3.x declaration and the portable version involves the wParam parameter, which grows to 32 bits under Win32. Therefore, replacing the WORD type with WPARAM is critical. The WPARAM type varies with the operating system, as does UINT: these types are 16 bits wide under Windows 3.x and 32 bits wide under Win32.

The other changes shown in the table are recommended for code clarity and portability. For example, WPARAM and LPARAM are automatically defined to be the correct types for message parameters, and CALLBACK will always be the correct declaration for window procedures.

A 32-bit wParam message parameter combined with the addresses and handles that grow to 32 bits, means that some messages must be repacked, as described in Handling 32-Bit Messages.


Removing Near and Far Type Declarations

Win32 does not distinguish between near and far addresses. Because the types NEAR and FAR are defined in WINDEF.H, they are automatically handled by the include file, which redefines them as empty strings for Win32. Thus, NEAR and FAR are ignored. If you do not include WINDEF.H, a convenient solution is to use the /D command-line option to replace the keywords by empty strings. For example:

/D_near=  /D_far= /D__near=  /D__far=


Using Proper Data Types

Windows 3.x source code often uses the type WORD interchangeably with types such as HWND and HANDLE. For example, the type cast (WORD) might be used to cast a data type to a handle:

hWnd = (WORD) SendMessage( hWnd, WM_GETMDIACTIVATE, 0, 0 );

This code compiles Windows 3.x applications correctly because both the WORD type and handles are 16 bits. But the code produces errors when compiled for Win32 because handles (such as HWND types) grow to 32 bits while the WORD type is still 16 bits.

Examine each occurrence of WORD casts and data definitions in your code, and revise as follows:

  • If a variable or expression is to hold a handle, replace WORD with HWND, HPEN, HINSTANCE, or another handle type.

  • If a variable or expression is a graphics coordinate or some other integer value that grows from 16 to 32 bits, replace WORD with UINT, and short with int.

  • Continue to use the WORD type only if the data type needs to be 16 bits for all versions of Windows (usually because it is a function argument or structure member).

In the portable version of the previous example, the (WORD) cast is replaced by (HWND):

hWnd = (HWND) SendMessage( hWnd, WM_GETMDIACTIVATE, 0, 0 );

In general, it is best to use the most specific type possible. Avoid using a generic handle type such as HANDLE, and use a more specific type such as HPEN. You should also define specific types for application-specific objects you create.


Handling 32-Bit Messages

Handles grow to 32 bits under Win32, so they can no longer be combined with other information and still fit into a 32-bit parameter (lParam). The handle now occupies all of lParam, so information formerly in the high or low word of lParam must now move to wParam.

Because the wParam message parameter also grows to 32 bits, it can hold the information that can no longer be held in lParam.

This figure illustrates how the parameter sizes change, and how information is repacked for WM_COMMAND, one of the messages affected.

Parameter Sizes

See the following topics on handling 32-bit messages:

  • Extracting Data from Messages with Portable Code

  • Using Proper Data Types


Extracting Data from Messages with Portable Code

The cleanest way to handle a repacked message is to revise your code so that it extracts needed information and stores it in local variables. This localizes message-packing issues to a few lines of your code.

For example, you can use the following code to handle the WM_COMMAND message:

          case WM_COMMAND:
            id = LOWORD(wParam);
            hwndChild = (HWND)(UINT)lParam;
            cmd = HIWORD(wParam);


Adjusting Calls to API Functions

Most of your source code is not affected by differences between the APIs of Windows 3.x and Win32. The underlying definitions in WINDOWS.H automatically adjust data to the correct size. But you may need to revise code if you call API functions in any of the following categories:

  • Graphics functions

  • Functions accessing “extra” window data

  • MS-DOS system calls

  • File Operations

  • Far-pointer functions

  • Functions getting list and combo box contents


Graphics Functions

Most of the Windows 3.x API functions that must be replaced return packed x- and y-coordinates.

In Windows 3.x, the x- and y-coordinates are 16 bits each and are packed into the 32-bit (DWORD) function return value, the largest valid size. In Win32, the coordinates are 32 bits each, totaling 64 bits, and are thus too large to fit into a single return value. Each Windows 3.x function is replaced by a Win32 function with the same name, but with an Ex suffix added. The Ex functions pass the x- and y-coordinates using an additional parameter instead of a return value. Both Win32 and Windows 3.x support these new functions.

The problematic graphics functions fall into two groups. The first group, functions that set coordinates, are shown in the following table with the Win32 versions.

Windows 3.x function | Portable version of function
MoveTo | MoveToEx
OffsetViewportOrg | OffsetViewportOrgEx
OffsetWindowOrg | OffsetWindowOrgEx
ScaleViewportExt | ScaleViewportExtEx
ScaleWindowExt | ScaleWindowExtEx
SetBitmapDimension | SetBitmapDimensionEx
SetMetaFileBits | SetMetaFileBitsEx
SetViewportExt | SetViewportExtEx
SetWindowExt | SetWindowExtEx
SetWindowOrg | SetWindowOrgEx

Each of the functions in the first column returns a value, although application code frequently ignores it. However, even if you do not care about the return value, you must replace the old function call with the new form. The old functions are not supported under Win32.

Each Ex function includes an additional parameter that points to a location to receive data. After the function call, this data provides the same information as the corresponding function’s return value. If you do not need this information, you can pass NULL to this parameter.

Under Windows 3.x, a call to the MoveTo function can be written as follows:

MoveTo( hDC, x, y );

In the portable version supported by both versions of Windows, the call to MoveTo is rewritten as follows. Note that the information returned by MoveToEx is ignored:

MoveToEx( hDC, x, y, NULL );

As a general rule, pass NULL as the last parameter unless you need to use the x- and y-coordinates returned by the Windows 3.x version. In the latter case, use the procedure outlined in the next few paragraphs for the Get functions.

The second group consists of functions in which the application code normally does use the return value. They are listed in the following table.

Windows 3.x function | Portable version of function
GetAspectRatioFilter | GetAspectRatioFilterEx
GetBitmapDimension | GetBitmapDimensionEx
GetBrushOrg | GetBrushOrgEx
GetCurrentPosition | GetCurrentPositionEx
GetTextExtent | GetTextExtentPoint
GetTextExtentEx | GetTextExtentExPoint
GetViewportExt | GetViewportExtEx
GetViewportOrg | GetViewportOrgEx
GetWindowExt | GetWindowExtEx
GetWindowOrg | GetWindowOrgEx

The 32-bit version of the GetTextExtent function has the Point suffix added because there is already a Windows 3.1 extended function GetTextExtentEx. Therefore, the new functions are GetTextExtentPoint and GetTextExtentExPoint.

As with the first group of functions, each Ex (and Point) version adds an additional parameter: a pointer to a POINT or SIZE structure to receive x- and y-coordinates. Because this structure is always the appropriate size for the environment, you can write portable code by:

  • Declaring a local variable of type POINT or SIZE, as appropriate.

  • Passing a pointer to this structure as the last parameter to the function.

  • Calling the function. The function responds by filling the structure with the appropriate information.

For example, the Windows 3.x version call to GetTextExtent extracts the x- and y-coordinates from a DWORD return value (stored in a temporary variable, dwXY):

DWORD   dwXY;

dwXY = GetTextExtent( hDC, szLabel1, strlen( szLabel1 ) );
rect.left = 0; rect.bottom = 0;
rect.right = LOWORD(dwXY);
rect.top = HIWORD(dwXY);
InvertRect( hDC, &rect );

The portable version passes a pointer to a temporary SIZE structure, and then it extracts data from the structure:

SIZE sizeRect;

GetTextExtentPoint( hDC, szLabel1, strlen( szLabel1 ), &sizeRect );
rect.left = 0; rect.bottom = 0;
rect.right = sizeRect.cx;
rect.top = sizeRect.cy;
InvertRect( hDC, &rect );


Functions That Access the Extra Window Data

The functions described in this section manipulate the “extra” data area of a window structure. This structure can contain system information and user-defined data. You specify the size of this data area by using the cbClsExtra and cbWndExtra members of the WNDCLASS structure when you register the window class.

The following Windows 3.x functions get or set 16 bits during each call: GetClassWord, GetWindowWord, SetClassWord, and SetWindowWord.

In Win32, each of these system-information items grows to 32 bits. Therefore, in Win32, you would use the following functions which access 32 bits at a time: GetClassLong, GetWindowLong, SetClassLong, and SetWindowLong.

Each of these functions takes two parameters: a window handle and an offset into the data area. These offsets differ depending on whether you are compiling for Windows 3.x or Win32.

The index values specifying these offsets correspond to each other as follows:

Windows 3.x | Win32 (nonportable)
GCW_CURSOR | GCL_CURSOR
GCW_HBRBACKGROUND | GCL_HBRBACKGROUND
GCW_HICON | GCL_HICON
GWW_HINSTANCE | GWL_HINSTANCE
GWW_HWNDPARENT | GWL_HWNDPARENT
GWW_ID | GWL_ID
GWW_USERDATA | GWL_USERDATA

In the case of GWW_HWNDPARENT, you can avoid calls to GetWindowLong and GetWindowWord, and instead use a single call to a new API function, GetParent. This API function returns a handle of the appropriate size. The following example illustrates a call to GetParent that has the same results as the #ifdef statements shown in the previous example:

hwndParent = GetParent( hWnd );

Remember that offsets may change for private data that you store in the window structure. You should review this code carefully and recalculate offsets for Win32, noting that some data types, such as handles, increase in size.


Porting MS-DOS System Calls

The DOS3Call API function in Windows 3.x must be called from assembly language. It is typically used to perform file I/O. In Win32, you should replace assembly language code that calls DOS3Call with the appropriate Win32 file I/O calls. Other (non-file) INT 21H functions should be replaced with the portable Windows API call as shown in the following table.

INT 21H subfunction | MS-DOS operation | Win32 API equivalent
0EH | Select Disk | SetCurrentDirectory
19H | Get Current Disk | GetCurrentDirectory
2AH | Get Date | GetDateAndTime
2BH | Set Date | SetDateAndTime
2CH | Get Time | GetDateAndTime
2DH | Set Time | SetDateAndTime
36H | Get Disk Free Space | GetDiskFreeSpace
39H | Create Directory | CreateDirectory
3AH | Remove Directory | RemoveDirectory
3BH | Set Current Directory | SetCurrentDirectory
3CH | Create Handle | CreateFile
3DH | Open Handle | CreateFile
3EH | Close Handle | CloseHandle
3FH | Read Handle | ReadFile
40H | Write Handle | WriteFile
41H | Delete File | DeleteFile
42H | Move File Pointer | SetFilePointer
43H | Get File Attributes | GetAttributesFile
43H | Set File Attributes | SetAttributesFile
47H | Get Current Directory | GetCurrentDirectory
4EH | Find First File | FindFirstFile
4FH | Find Next File | FindNextFile
56H | Change Directory Entry | MoveFile
57H | Get Date/Time of File | GetDateAndTimeFile
57H | Set Date/Time of File | SetDataAndTimeFile
59H | Get Extended Error | GetLastError
5AH | Create Unique File | GetTempFileName
5BH | Create New File | CreateFile
5CH | Lock | LockFile
5CH | Unlock | UnlockFile
67H | Set Handle Count | SetHandleCount


File Operations

You may need to increase the size of fixed-length buffers for filenames and environment strings. Windows 95 and Windows NT support filenames of up to 256 characters, rather than the 8.3 format supported by MS-DOS. You can make code more portable by allocating longer buffers or by using dynamic memory allocation. If you want to conserve memory under Windows 3.x, you can use #ifdef statements to allocate buffers of the proper length for the environment. You can also use macros such as _MAX_PATH and _MAX_FNAME, defined in STDLIB.H.

Windows 95 and Windows NT require stricter use of file open and close operations than Windows 3.x. There are some combinations of open and close functions (for example, mixing _open with _lclose) that may work in code for Windows 3.x, but require revision to work correctly with Windows 95 and Windows NT.

You may also need to make changes in low-level file I/O. In porting Windows 3.x code, some developers change from using the Windows API file I/O functions (such as _lopen and _lread) to using the C run-time low-level I/O functions (such as _open and _read). All versions of the Windows API support only binary mode, not text mode, but the C run-time calls use text mode by default. Therefore, when changing from the Windows file I/O to the C run-time versions, open files in binary mode by doing one of the following:

  • Link with BINMODE.OBJ, which changes the default mode for all file-open operations.

  • Open the individual files with _O_BINARY flag set.

  • Use setmode to change an open file to _O_BINARY.


Far-Pointer Functions

Windows 3.x provides functions for memory and file manipulation using far pointers, which have the form _f xxxx. In Win32, these functions are replaced by similarly-named functions of the form xxxx, because there is no need for far pointers in Win32. (The _f prefix is dropped from the name.)

The WINDOWSX.H file defines the _f xxxx function names so that in Win32, the _f xxxx function names are equated to corresponding functions that are still supported. This means that as long as you include WINDOWSX.H, you don’t have to rewrite calls to these functions. Some of the definitions are:

#define _fmemcpy      memcpy
#define _fstrcpy      strcpy
#define _fstrcmp      strcmp
#define _fstrcat      strcat


Functions Getting List and Combo Box Contents

The Win32 API contains two new functions, shown in the following table, that provide an improved means of extracting list and combo box contents. In each case, you use the portable version of the function to specify a buffer size for a string that receives the information.

Windows 3.x function | Portable version of the function
DlgDirSelect | DlgDirSelectEx
DlgDirSelectComboBox | DlgDirSelectComboBoxEx

For example, Windows 3.x code might contain the following function call:

DlgDirSelect( hDlg, lpString, nIDListBox );

This line of code should be replaced by the following call to DlgDirSelectEx:

DlgDirSelectEx( hDlg, lpString, strlen(lpString), nIDListBox );


Revising the WinMain Function

You need to revise the WinMain function if either of the following is true:

  • Your application needs to know when another instance of the application is running, or

  • You need to access the command line.

Otherwise, the code in this function generally needs no change.

The parameter list for WinMain is the same for Win32 and Windows 3.x:

int PASCAL WinMain(hInstance, hPrevInstance, lpCmdLine, nCmdShow)

Note that under Win32, the hPrevInstance parameter is always passed NULL (see the next section, Initializing Instances). As with 16-bit Windows 3.x, the lpCmdLine parameter points to a string containing the entire command line.


Initializing Instances

The hPrevInstance parameter is always passed NULL in Win32. This causes each instance of an application to act as though it were the only instance running. The application must register the window class, and it cannot access data used by other instances, except through standard interprocess communication techniques such as shared memory or DDE. Calls to GetInstanceData must be replaced with these techniques.

Before registering a window class, source code for Windows 3.x normally tests hPrevInstance to see whether another instance of the application is already running. This code needs no change, because under Win32, it will always register the window class.

Some applications must know whether other instances are running. Sometimes this is because data sharing is required. More frequently, it is because only one instance of the application should run at a time. Examples of this latter case include Control Panel and NT's Task Manager.

Applications cannot use hPrevInstance to test for previous instances under Win32. An alternative method must be used, such as creating a unique named pipe, creating or testing for a named semaphore, broadcasting a unique message, or calling FindWindow.


Special Considerations for Advanced Applications

Additional revisions may sometimes be necessary for applications that use advanced API calls or coding tricks. If your application is fairly complex, you should scan this section to make sure that you don’t need to make additional changes.

  • Revising Advanced API Calls such as .INI file access, setting focus, and mouse capture

  • Solving Problems Due to C Coding Techniques


Revising Advanced API Calls

Applications may need further revision if they use API calls dealing with any of the following: accessing .INI files, setting focus and active window, capturing the mouse, and sharing graphical objects.

  • Profile Strings and .INI Files

  • Focus, Mouse Capture, and Localized Input

  • Window Focus

  • Mouse Capture

  • Shared Graphical Objects


Profile Strings and .INI Files

Although Windows 95, Windows NT, and Win32s are all examples of Win32, Windows 95 and Windows NT have some features not present in Win32s.

Windows 3.x applications can access .INI files directly. In Windows 95 and Windows NT, however, such code doesn’t work because the information in .INI files is replaced by a registration database. This database offers some advantages, including security controls that prevent an application from corrupting system information, error logging, remote software updating, and remote administration of workstation software.

You can write portable code by using the profile API supported by Windows 3.x and all versions of Win32, including Windows 95 and Windows NT. Call the GetProfileString and WriteProfileString API functions instead of accessing .INI files directly. These functions use whichever underlying mechanism (.INI file or registration database) is supported by the environment you are compiling for.


Focus, Mouse Capture, and Localized Input

Windows 95 and Windows NT differ from Windows 3.x in that each thread of execution has its own message pump. This change affects window focus and mouse capture.


Window Focus

In Win32, each thread of execution can set or get the focus only to windows created by the current thread. This prevents applications from interfering with each other. One application’s delay in responding cannot cause other applications to suspend their response to user actions, as often happens in Windows 3.x.

Consequently, the following API functions work differently under Win32:

GetActiveWindow( VOID ) | SetActiveWindow( HWND )
GetCapture( VOID ) | SetCapture( HWND )
GetFocus( VOID ) | SetFocus( HWND )
ReleaseCapture( VOID ) |

The Get functions in the preceding list can now return NULL, which could not happen in Windows 3.x. Therefore, it’s important to test the return value of GetFocus before using it. Instead of returning the window handle of another thread, the function returns NULL. For example, you call GetFocus and another thread has the focus. Note that it’s possible for a call to GetFocus to return NULL even though an earlier call to SetFocus successfully set the focus. Similar considerations apply to GetCapture and GetActiveWindow.

The Set functions can only specify a window created by the current thread. If you attempt to pass a window handle created by another thread, the call to the Set function fails.


Mouse Capture

Mouse capture is also affected by the Windows 95 and Windows NT localized input queues. If the mouse is captured on mouse down, the window capturing the mouse receives mouse input until the mouse button is released, as in Windows 3.x. But if the mouse is captured while the mouse button is up, the window receives mouse input only as long as the mouse is over that window or another window created by the same thread.


Shared Graphical Objects

Win32 applications run in separate address spaces. Graphical objects are specific to the application and cannot be manipulated by other processes as in Windows 3.x. A handle to a bitmap passed to another process cannot be used because the original process retains ownership.

Each process should create its own pens and brushes. A cooperative process may access the bitmap data in shared memory (by way of standard interprocess communications) and create its own copy of the bitmap. Bitmap alterations must be communicated between the cooperative processes by way of interprocess communication, such as DDE.

Win32 adds an explicit ownership transfer API function for graphical objects to explicitly allow cooperative applications to share graphical objects.


Solving Problems Due to C Coding Techniques

Some portability problems can be caused by coding techniques that do not translate successfully to other memory models and processors. You can avoid these problems by not using segmented memory. The header files will then handle standard pointers and manage memory correctly.

  • Memory and Pointers

  • Structure Alignment

  • Ranges and Promotions


Memory and Pointers

To be portable, source code must avoid any techniques that rely on the 16-bit segment:offset address structure, because all pointers are 32 bits in size under Win32 and use flat rather than segmented memory.

This difference in pointer structure is usually not a problem unless the code uses HIWORD, LOWORD, or similar macros to manipulate portions of the pointer.

For example, in Windows 3.x, memory is allocated to align on a segment boundary, which makes memory allocation functions return a pointer with an offset of 0x0000. The following code exploits this fact to run successfully under Windows 3.x:

ptr2 = ptr1 = malloc();               // ptr2 = xxxx:0000
LOWORD( ptr2 ) = index * elementsize; // Place offset of array element
                                      //   into ptr2 low word

Such code does not work properly under Win32. But standard pointer constructs, such as the following, always result in portable code:

ptr1 = malloc();         // Set ptr1 to start of memory block
ptr2 = &ptr1[i];         // Place offset of array element

Here are some other guidelines for dealing with pointers:

  • All pointers, including those that access the local heap, are 32 bits under Win32.

  • Addresses never wrap, as they can with the low word in segmented addressing. For example, in Windows 3.x, an address can wrap from 1000:FFFF to 1000:0000.

  • Structures that hold near pointers in Windows 3.x must be revised because all pointers are 32 bits in Win32. This may affect code that uses constants to access structure members, and it may also affect alignment.


Structure Alignment

Applications should generally align structure members at addresses that are “natural” for the data type and the processor involved. For example, a 4-byte data member should have an address that is a multiple of four.

This principle is especially important when you write code for porting to multiple processors. A misaligned 4-byte data member, which is on an address that is not a multiple of four, causes a performance penalty with an 80386 processor and a hardware exception with a MIPS® RISC processor. In the latter case, although the system handles the exception, the performance penalty is significantly greater.

The following guidelines ensure proper alignment for processors targeted by Win32:

Type | Alignment
char | Align on byte boundaries
short (16-bit) | Align on even byte boundaries
int and long (32-bit) | Align on 32-bit boundaries
float | Align on 32-bit boundaries
double | Align on 64-bit boundaries
structures | Largest alignment requirement of any member
unions | Alignment requirement of the first member

The compiler automatically aligns data in accordance with these requirements, inserting padding in structures up to the limit (default pack size) specified by the /Zp option or #pragma pack. For example, /Zp2 permits up to 1 byte of padding, /Zp4 permits up to 3 bytes of padding, and so on. The default pack size for Windows 3.x is 2, whereas the default for Win32 is 8. As a consequence:

  • If you have specified a packing limit with /Zp or #pragma pack, you may not get the proper alignment (the default value) for Win32.

  • The different default setting for Win32 can impact your source code by changing the offsets of some structure members. Examine your code closely to see whether you have hard-coded these offsets, or whether your code makes assumptions based on a certain default pack size.


Ranges and Promotions

Occurrences of int, unsigned, and unsigned int indicate potential portability problems because size and range are not constant. Data that would not exceed its range in Win32 could exceed range in Windows 3.x. Sign extension also works differently, so exercise caution in performing bitwise manipulation of this data.

Source code that relies on wrapping often presents portability problems and should be avoided. For example, a loop should not rely on an unsigned variable wrapping at 65535 (the maximum value in Windows 3.x) back down to 0.


Porting 16-Bit MFC to 32-Bit MFC

Home | Overview | How Do I | FAQ | Details

This article gives tips for porting your MFC application from 16-bit to 32-bit.

Although most of the changes in Windows parameters are handled for you within the framework, there are some changes you will have to make manually. They are described in this article, which covers:

  • Summary of differences between 16-bit and 32-bit MFC

  • Changing message handlers

  • Using the collection classes

The 32-bit CTime class differs from the 16-bit version. For details, see the article Date and Time: SYSTEMTIME Support.


Summary of Differences Between 16-Bit and 32-Bit MFC

Version 3.0 and later of the Microsoft Foundation Class Library (MFC) uses the Win32 application programming interface (API). Many of the Win32 API functions are encapsulated in MFC class member functions. However, one of the fundamental tenets of programming with MFC is that you can always make direct calls to the Windows API.

Differences between the 16-bit versions of MFC and the 32-bit versions include:

  • The packing of lParam and wParam in the CWnd members OnCommand and OnParentNotify has changed from 16-bit MFC. For more information, see Changing Message Handlers.

  • The CTime class has constructors that accept system and file times from Win32. For more information, see Date and Time: SYSTEMTIME Support.

  • The class library provides new member functions that wrap many Win32 API functions, including many Win32 GDI functions.

  • Class CWinThread supports multithreaded programming. For more information, see the article Multithreading with C++ and MFC.

  • Most of the class library is enabled for Unicode and for Double-Byte Character Set (DBCS) programming. The database classes are the exception. This enabling means that many class member functions now take character and string parameters of types based on type TCHAR.

  • The 32-bit MFC static link and dynamic-link libraries are named differently from the 16-bit libraries. See MFC Library Versions.

  • Some features of the class library are no longer available in the 32-bit environment. See the article Features No Longer Available in MFC.


Changing Message Handlers

Window handles in the Win32 API are 32-bit values; consequently, the WPARAM type has been widened from 16 to 32 bits to accommodate this change. This widening often necessitates repacking the values carried by the wParam and lParam parameters.

A 16-bit application, written for Windows without using the framework, requires a considerable amount of code rewriting to port successfully to 32-bit. Each window procedure declaration must be modified, as well as the message-handling code within the procedure.

The MFC class library accommodates most of these changes internally. The framework hides the window procedure from you, unpacks wParam and lParam, and passes the properly unpacked values to you in message handlers. The only two instances that require your attention are functions that override the CWnd::OnCommand and CWnd::OnParentNotify message handlers, where the framework passes wParam or lParam directly from Windows to you.

The framework also unpacks the wParam and lParam values associated with a WM_COMMAND message to implement message-map entries. The framework properly unpacks the values as appropriate for Windows version 3.x or Win32 with no attention from you.

CWnd::OnCommand Changes

If your application overrides OnCommand, check the code carefully and modify it so that it unpacks wParam and lParam correctly. Your 16-bit override of OnCommand may compile successfully, but will not execute correctly.

When the framework receives a WM_COMMAND message, it calls the CWnd::OnCommand member function with the following arguments:

virtual BOOL OnCommand( WPARAM wParam, LPARAM lParam );

A command ID, a control handle, and a notification message can be packed in wParam and lParam, depending on the circumstances of the call.

You don’t need to change the way you extract the command ID; it is packed the same way in both environments. You can extract it this way:

UINT nID = LOWORD(wParam);

You extract the remaining two values in this way in the 16-bit framework:

HWND hWndCtrl = (HWND)LOWORD(lParam);       //Control handle
int nCode = HIWORD(lParam);                 //Notification code

You extract them this way in the 32-bit framework:

HWND hWndCtrl = (HWND)lParam;              //Control handle
int nCode = HIWORD(wParam);                //Notification code

In both the 16-bit and 32-bit versions, if the OnCommand message is from an accelerator, the value retrieved in nCode is 1. If the message is from a menu, the value in nCode is 0.

CWnd::OnParentNotify Changes

As with OnCommand, carefully check any code in your application that overrides OnParentNotify and modify it so that it unpacks values from lParam correctly. Your 16-bit override of OnParentNotify will compile successfully, but will not execute correctly.

The framework calls the CWnd::OnParentNotify member function with the following arguments:

afx_msg void OnParentNotify( UINT message, LPARAM lParam );

The OnParentNotify member function is called for the parent of a child window in two cases: when the mouse is clicked over a child window, and when a child window is created or destroyed.

When the message parameter is equal to WM_CREATE or WM_DESTROY, the framework’s 16-bit packing of lParam puts the child window handle in the low-order word and the identifier of the child window in the high-order word. For the 32-bit framework, the child window handle has been widened and now takes up all of lParam; the child window identifier is unavailable.

If your Win32 code in OnParentNotify requires the child ID, retrieve it like this:

CWnd* pChild = FromHandle( (HWND)lParam );
int nID = pChild->GetDlgCtrlID();

In this example, FromHandle returns the CWnd object attached to the child window handle. The GetDlgCtrlID member function returns the child window ID. You could also retrieve the child ID by passing the child handle directly to the Windows GetDlgCtrlID function, but the code above also retrieves a pointer to the child CWnd object.

The pointer returned in pChild is temporary and should not be stored for use beyond the scope of OnParentNotify.


Using the Collection Classes

With 16-bit Windows, the CObArray class and all related array collection classes are constrained by 16-bit memory models and must fit within a single 64K segment.

With Win32, the number of elements that can fit within a framework array collection is limited only by the amount of available memory. The maximum number of collection elements is the largest possible value of a UINT, which is much larger than a typical computer’s memory. The increase in maximum collection size should have little effect upon your code because a framework collection simply throws a CMemoryException when it reaches its memory limit in both the 16-bit version and the 32-bit version of the framework.

See Also Date and Time: SYSTEMTIME Support


Changes in MFC Versions

Home | Overview | How Do I | FAQ | Details

This section discusses changes in MFC from previous versions. Find out more about the upgrade that applies to your application.

  • Changes from MFC Versions 2.0 and 2.5

  • Changes from MFC Versions 3.x

  • MFC Windows 95 Support

  • Changes from MFC Versions 4.x

  • Changes from MFC Version 4.22


Changes from MFC Versions 2.0 and 2.5

You may be upgrading to version 3.0 of the Microsoft Foundation Class Library from one of the previous 16-bit versions: either MFC version 2.0 or 2.5, which are part of Visual C++ versions 1.0 and 1.5, respectively.

This article covers the following topics:

  • Upgrading from MFC Version 2.5

  • Upgrading from MFC Version 2.0

  • Changes from MFC Version 2.0 32-Bit Edition

  • Features No Longer Available in MFC


Upgrading from MFC Version 2.5

  • Support for 32-bit programming.

    MFC version 3.0 targets Win32 platforms, including Intel Win32s, Windows NT, and Windows 95, as well as the Macintosh® and Windows NT on MIPS, Alpha, and PowerPC platforms. The same MFC code works for all of the different targets.

  • Extended Win32 API coverage.

    The coverage includes new GDI functionality such as Beziers and Paths and a number of other Win32 “USER” APIs.

  • Support for C++ exceptions.

    MFC uses C++ exceptions. The MFC exception-handling macros are also provided for backward compatibility and compiler portability.

  • Collection classes based on C++ templates.

    These classes make it easier to derive your own type-safe collection classes.

  • Support for creating property sheets, also referred to as “tab dialog boxes,” in your programs.

    You can create property sheets containing tabs like those found in Microsoft Word for Windows version 6.0 and Visual C++. This support is in classes CPropertyPage and CPropertySheet.

  • Support for creating "dockable" tool bars in your programs.

    You can create toolbars that the user can drag to various parts of the main frame window. API member functions for dockable toolbars are in classes CToolBar and CFrameWnd.

  • Support for "tool tips" like those in Microsoft Excel.

    When the user moves the mouse over a toolbar button in your application, a small box is shown on top of the button to describe the action that would be performed.

  • Support for Unicode and Double-Byte Character Sets (DBCS).

    Your applications can be more easily internationalized using Unicode or DBCS strings.

  • Support for 3D controls.

    Simply call CWinApp::Enable3dControls from your InitInstance function to get a three-dimensional appearance in your dialog boxes.

  • Support for frame windows with thin caption bars, such as those used for Visual C++ property windows.

    See class CMiniFrameWnd in the Class Library Reference.

  • Message-map support for ranges of command IDs and control IDs.

    For example, you can map a range of command IDs to a single message handler.

  • New CString member functions, such as Format, which resembles the sprintf run-time function.

  • Automatic linking of the correct version of the MFC library and any other required libraries, such as the Win32 libraries, OLE libraries, or ODBC libraries.


Upgrading from MFC Version 2.0

If you’re upgrading from version 2.0, you get the following support in addition to the features listed under Upgrading from MFC Version 2.5:

  • Support for ActiveX Controls (formerly OLE).

    New MFC classes make it easier to write visual editing servers and containers and to implement Automation (formerly OLE Automation) in your applications. See OLE Topics.

  • Support for data access with Open Database Connectivity (ODBC).

    MFC database classes help you manipulate data in databases for which you have the appropriate 32-bit ODBC driver. See Database Topics (ODBC).

See Also DLL Topics, Toolbars: Docking and Floating, Toolbars: Tool Tips, Strings: Unicode and Multibyte Character Set (MBCS) Support, Property Sheets, Collections Topics, Exception Handling Topics (MFC), International Programming Topics


Changes from MFC Version 2.0 32-Bit Edition

This article discusses changes in version 3.0 of the Microsoft Foundation Class Library for users of the 32-bit version of MFC version 2.0 (sometimes called MFC version 2.1), which is part of Visual C++ 1.0 32-Bit Edition. Changes include:

  • Full support for writing multithreaded applications.

    You can use MFC functionality in both the primary thread of execution and in secondary threads.

  • Support for OLE.

    MFC OLE classes make it easier to write OLE servers and containers and to implement Automation (formerly OLE Automation) in your applications. See OLE Topics.

  • Support for data access with Open Database Connectivity (ODBC).

    MFC database classes help you manipulate data in databases for which you have the appropriate 32-bit ODBC driver. See Database Topics (ODBC).

  • Support for MFC packaged in a shared DLL, called AFXDLL.

    To use AFXDLL, a set of DLLs that contains the entire 32-bit Microsoft Foundation Class Library, use “/D_AFXDLL” in your compiler options and one of the “MFC30” DLLs in your linker options.

    Using AFXDLL results in smaller executable files than statically linking the class library with your application. This is particularly useful if you have several applications that run at the same time; they can share the DLL.

    AFXDLL is the default when you create an MFC application with AppWizard.

  • WIN32_LEAN_AND_MEAN.

    To improve build times and reduce the size of your application’s precompiled header, MFC defines the symbol WIN32_LEAN_AND_MEAN. This definition lists a group of less commonly used header files that MFC does not automatically include through including AFXWIN.H.

    To see the list of header files specifically excluded from MFC builds, look at the definition of WIN32_LEAN_AND_MEAN in WINDOWS.H. If you need the definitions provided by any of those files, you must explicitly include the appropriate file yourself.

    WIN32_LEAN_AND_MEAN was not defined in MFC version 2.1, and all of the extra headers were included.

See Also Changes from MFC Versions 2.0 and 2.5, Multithreading with C++ and MFC, DLL Topics, MFC Library Versions


Features No Longer Available in MFC

This topic lists features that were discontinued starting in version 3.0 of the MFC library. Many of the changes result from similar changes in Win32.

  • VBX controls (not supported on 32-bit platforms).

  • Microsoft Windows for Pen Computing classes (not supported under Windows NT; Pen support is available under Windows 95, but MFC does not supply Pen classes).

  • The UnrealizeObject function has been deleted in Win32.

    Since calls to CGdiObject::UnrealizeObject are common in programs written for Windows version 3.x, yet are now unnecessary, this member function is retained for backward compatibility. It now always returns a nonzero value, without making an underlying Win32 function call. Calls to CGdiObject::UnrealizeObject should not be made in new Win32 programs and should be removed from existing programs eventually.

  • The QueryAbort function has been deleted in Win32; the CDC::QueryAbort member function has also been deleted.

    If your program needs this functionality, you should create a member function that calls your AbortProc callback function directly.

  • The console library variants, NAFXCR.LIB and NAFXCRD.LIB, are no longer available.

    You should now link with NAFXCW.LIB or NAFXCWD.LIB with no loss in capability or content from projects that previously used NAFXCR.LIB or NAFXCRD.LIB.

See Also Changes from MFC Version 2.0 32-Bit Edition, Changes from MFC Versions 2.0 and 2.5


Changes from MFC Versions 3.x

This article describes the most common problems that can occur when porting an application written with MFC 3.x (the MFC included with Visual C++ 2.x) to MFC 4.x. The following porting issues are discussed:

  • Window classes are no longer pre-registered by MFC.

  • CWinApp::m_templateList no longer exists.

  • CRuntimeClass::m_pfnConstruct is now m_pfnCreateObject.

  • Changes in CStatusBar and CToolBar implementation can break previous code.

  • Changes in CPropertySheet implementation can break previous code.

  • CPropertySheet always changes its font to the default font.

  • Do property sheet modifications in OnInitDialog after a call to the base class.

  • CPropertySheet::DoModal causes a first chance exception on Windows 95 (the exception can be ignored).

  • Property sheets now have a minimum width.

  • CToolBar requires a minimum button size.

  • Do not replace CFileDialog's default hook procedure.

  • Altering CFileDialog's standard Explorer interface requires a call to GetParent.

  • CFileDialog member functions GetFileName and GetFileTitle are functionally reversed.

  • MFC threads cannot be created during DLL startup.

  • Regular DLLs using the MFC shared library require AFX_MANAGE_STATE in exported functions.

  • MFCANS32.DLL no longer exists: OLE functions in MFC applications now require Unicode arguments.

Knowledge Base articles referenced in this article are available by connecting to http://www.microsoft.com/kb/. Choose Visual C++ in the Choose a Microsoft product or technology drop-down list. Enter the article number in the Enter a Search Phrase text box, then click Begin Search.

Window Classes Are No Longer Pre-Registered by MFC

Before MFC version 4.0, MFC pre-registered four window classes, as documented in MFC Technical Note 1. These WNDCLASSes were AfxWnd, AfxFrameOrView, AfxMDIFrame, and AfxControlBar.

Most code that prevented more than one instance of an application relied on these classes, but, as of version 4.0, the classes are not registered until a window of that type is created.

Custom WNDCLASS-based windows that rely on ::GetClassInfo to retrieve class information from the MFC window classes will likely fail to be displayed and will send the message that Window creation failed and GetLastError returned the value 0x57F (ERROR_WNDCLASS_DOES_NOT_EXIST). The message is sent to the debug output window if MFC tracing is turned on. The error message corresponding to this error is "Cannot find window class".

To prevent this situation, provide all of the necessary information when registering custom window classes with RegisterClass or AfxRegisterClass and do not rely on ::GetClassInfo to retrieve class values for MFC window classes.

For more information, see the Knowledge Base article Q140596 and the Knowledge Base sample Q141752.

CWinApp::m_templateList No Longer Exists

The m_templateList member variable of CWinApp was undocumented in MFC 3.x, but was used commonly enough to create porting problems. The recommended way to access the templates for an application is to use the GetFirstDocTemplatePosition and GetNextDocTemplate member functions of CWinApp.

For more information, see the Knowledge Base article Q106455.

CRuntimeClass::m_pfnConstruct Is Now m_pfnCreateObject

The member variable m_pfnConstruct was a documented member of CRuntimeClass in MFC versions prior to 4.0, but the name was changed to m_pfnCreateObject to reflect a change in parameters and return value. The documentation included with Visual C++ 4.0 was not updated to reflect this change and incorrectly references the old member variable name.The documentation for Visual C++ 4.1 and later, however, is up to date.

Changes in CStatusBar and CToolBar Implementation Can Break Previous Code

CStatusBar and CToolBar now wrap the functionality of the Win32 common controls. Any code that relied on or modified the private, undocumented implementation of these classes will likely break when compiled for MFC 4.0. These two common controls support a greater range of common customizations than the previous default MFC implementation and do not require significant overrides of the MFC source for such tasks as constructing palette bars or making resizable toolbars. If needed, the old implementation of these two classes is still available as the COldStatusBar and COldToolBar classes.

Changes in CPropertySheet Implementation Can Break Previous Code

Much of the MFC implementation of CPropertySheet has now changed to wrap the Windows Property Sheet common control. There have been formatting and sizing changes. More importantly, if previous code used any of the private MFC implementation of CPropertySheet, it will likely break since most of the undocumented members of that class are no longer there.

CPropertySheet Always Changes Its Font to the Default Font

CPropertySheet now always changes its font to the default font. Even if the font of the property pages is changed in the resource editor, property pages will be displayed at run-time with the system font. If it is necessary to change the font, call SetFont in OnInitDialog and then do an appropriate MoveWindow to resize the sheet and move and resize all controls on the page. Also, the property sheet is set back to its original size whenever a page is activated, so it is necessary to resize the page in response to a click on the tab control. For more information, see the Knowledge Base article Q142170.

Do Property Sheet Modifications in OnInitDialog After a Call to the Base Class

Property sheet modifications should be done in OnInitDialog after a call to the base class. During CPropertySheet::OnInitDialog, the property sheet is resized and the four standard buttons (OK, Cancel, Apply, and Help) are hidden at the bottom of modeless property sheets. The proper place to modify the size of the sheet or to customize the four property sheet buttons is in OnInitDialog after the call to the base class. It was common in previous versions of MFC to hide some of the buttons shown with a modal property sheet in OnCreate. These buttons can now be removed easily by modifying styles in the PROPSHEETHEADER structure CPropertySheet::m_psh. For more information, see the Knowledge Base articles Q140585 and Q141039.

CPropertySheet::DoModal Causes a First Chance Exception on Windows 95

CPropertySheet::DoModal causes a first chance exception on Windows 95 because the property page sets required styles in the dialog resource. The operating system needs to handle this and the message can be ignored. If you surround the DoModal call with a try/catch(...) block in an effort to handle the exception yourself, you will get a stack fault. For more information, see DoModal.

Property Sheets Now Have a Minimum Width

The minimum width of a CPropertySheet window is the size of the four buttons (OK, Cancel, Apply, and Help) that would show up along the bottom of a modal property sheet. This width applies even to modeless property sheets, which do not show the four buttons along the bottom.

CToolBar Requires a Minimum Button Size

Toolbars now require that the width of the button size be at least 7 pixels greater than the image size. The documentation that ships with Visual C++ 4.0 was not updated to reflect this change and is incorrect. The ASSERT that MFC version 4.0 uses to verify correct parameters in SetSizes also incorrectly checks for the old value of 6. There are other limits on the sizes of the toolbar, buttons, and images, but these are correctly covered by ASSERT statements in the MFC source and have not changed since MFC 3.x. For more information, see the Knowledge Base article Q141444.

Do Not Replace CFileDialog's Default Hook Procedure

MFC always specifies its own hook procedure, _AfxCommDlgProc, for the Open File Dialog during the construction of the CFileDialog object so that it can route notifications for the dialog to the proper handlers. As of MFC 4.x, this hook procedure is used to subclass the CFileDialog object to the Open File Dialog window. If the hook procedure is replaced, subclassing will not happen and any attempt to use the CFileDialog (or an embedded control variable on it) as a window will fail.

Altering CFileDialog's Standard Explorer Interface Requires a Call to GetParent

When you use the Windows Explorer-style CFileDialog (the default on Windows 95), MFC 4.x assumes the Windows Explorer model of customization. This implies that custom improvements to the File dialog are included on a separate template that is added around the standard Windows Explorer dialog.

In MFC 4.x, the actual CFileDialog window is a child dialog of the main File Common Dialog, even if you are not providing a template to customize the dialog. Therefore, if you have a need to alter the standard Windows Explorer interface by moving or hiding controls, prefix all GetDlgItem calls to Windows Explorer controls with GetParent. For example, GetParent()->GetDlgItem(IDOK) will return a pointer to the Open/Save button on the Windows Explorer dialog. However, this is not recommended because code which relies on the details of the standard Windows Explorer dialog controls will break if the Windows Explorer layout is changed in the future.

CFileDialog Member Functions GetFileName and GetFileTitle Are Functionally Reversed

MFC 4.0 implementation of CFileDialog member functions GetFileName and GetFileTitle is reversed from previous versions of MFC. For example, in MFC 4.0, given the file "C:\ARTICLE.TXT", CFileDialog::GetFileName returns "ARTICLE.TXT" and CFileDialog::GetFileTitle returns "ARTICLE". Previous versions of MFC returned exactly the opposite. The functions have been changed to work like the Win32 API functions of the same names. However, the documentation included with Visual C++ 4.0 was not updated to reflect these changes. The documentation for Visual C++ 4.1, however, is up to date.

MFC Threads Cannot Be Created During DLL Startup

In previous versions of MFC, it was possible to create a thread during the startup of an MFC DLL. This required calling AfxBeginThread or CWinThread::CreateThread in DllMain, in RawDllMain, in InitInstance in the DLL, or in any functions called by these. Due to synchronization of MFC thread startup code and blocking at DllMain during DLL_PROCESS_ATTACH and DLL_THREAD_ATTACH, this is no longer permitted. MFC 4.0 DLLs that attempt to do this will hang when loaded by an application. For more information, see the Knowledge Base article Q142243.

Regular DLLs Using the MFC Shared Library Require AFX_MANAGE_STATE in Exported Functions

Previously, the USRDLL model required that MFC be statically linked to the DLL. It is now possible to link dynamically to the MFC40.DLL from a Regular DLL, the new term for _USRDLLs. However, to convert a _USRDLL to a Regular DLL using MFC in a shared library, you need to make sure that you manage your module state information correctly. The single line:

AFX_MANAGE_STATE(AfxGetStaticModuleState());

should be added to the beginning of any function exported from the DLL which operates on MFC objects. If the module state is not switched appropriately, it could cause the following problems: dialogs and windows fail at creation in a DLL because of missing resources, functions for the wrong application object get called and cause stack overflow or unpredictable results, unrecognized run-time class information, bad window to MFC object handle map linkage, and more. For more information, see the Knowledge Base article Q140850 and MFC Technical Note 58.

MFCANS32.DLL No Longer Exists: OLE Functions in MFC Applications Now Require Unicode Arguments

In MFC 3.x, a special DLL was used (MFCANS32.DLL) to automatically convert between Unicode and MBCS when OLE interfaces were called. MFC 4.x does not use this DLL and instead talks directly to the Unicode OLE interfaces. To handle this change, MFC applications now must pass the correct type of parameters — whether Unicode or MBCS — to OLE functions. MFC 4.0 has provided a number of macros that makes this task easier. For more information, see MFC Technical Note 59.


MFC Windows 95 Support

This article describes how MFC version 4.x supports programming for Windows 95.

The most important change is that MFC versions 4.0 and later fully supports programming for Microsoft Windows 95. Your MFC applications can run on either Windows 95 or Windows NT version 3.51 and later. Under each environment, your applications have the appropriate visual look.

Here are the key features for Windows 95:

  • New common control classes

  • New implementations for control bar and property sheet classes

  • Rich edit classes

  • Other new controls

  • New common dialogs

  • Ability to easily customize the File Open dialog box

For more information on these Windows 95 features, see Windows 95 Functionality.

New Common Control Classes

MFC supplies classes for new Win32 common controls, including the rich edit control. These controls are available under Windows 95 and Windows NT version 3.51 or later. They supplement Windows common controls such as list boxes, edit controls, and combo boxes. Most of the new control classes were released in beta quality with MFC version 3.1; version 4.0 supplies them in finished form and includes controls not released with version 3.1.

For more on using the common control classes, see Control Topics.

  • CAnimateCtrl A window that displays successive frames of an Audio Video Interleaved (AVI) clip during a lengthy operation.

  • CHeaderCtrl A resizable button that appears above a column of text, allowing the user to display more or less information in the column.

  • CHotKeyCtrl A window that enables the user to create a hot key. A "hot key" is a key combination that the user can press to perform an action quickly.

  • CImageList A collection of images used to efficiently manage large sets of icons or bitmaps.

  • CListCtrl A window that displays a collection of items each consisting of an icon and a label.

  • CProgressCtrl (Also known as a "progress bar control.") A window that an application can use to indicate the progress of a lengthy operation.

  • CRichEditCtrl A window in which the user can enter and edit text with character and paragraph formatting. The control can include embedded OLE objects. See Rich Edit Classes for related information.

  • CSliderCtrl (Also known as a "trackbar.") A window containing a slider and optional tick marks that sends notification messages to indicate changes in its position.

  • CSpinButtonCtrl (Also known as an "up-down control.") A pair of arrow buttons that the user can click to increment or decrement a value, such as a scroll position or a number displayed in a companion control.

  • CStatusBarCtrl A horizontal window in a parent window in which an application can display various kinds of status information. This control resembles the MFC CStatusBar class.

  • CTabCtrl Analogous to the dividers in a notebook or the labels in a file cabinet. By using a tab control, an application can define multiple pages for the same area of a window or dialog box. (See also MFC class CPropertySheet.)

  • CToolBarCtrl A window that contains one or more command-generating buttons. This control resembles the MFC CToolBar class.

  • CToolTipCtrl A small pop-up window that displays a single line of text describing the purpose of a toolbar button or other tool in an application.

  • CTreeCtrl (Also known as a "tree view control.") A window that displays a hierarchical list of items, such as the headings in a document, the entries in an index, or the files and directories on a disk. Each item consists of a label and an optional bitmapped image, and each item can have a list of subitems associated with it.

New Implementations for Control Bar and Property Sheet Classes

The following MFC classes have been reimplemented using some of the new Windows common controls listed earlier in this article:

  • CToolBar Now uses the toolbar control represented by class CToolBarCtrl. Class COldToolBar provides the previous implementation for backward compatibility so that you can continue to use your customizations from the previous versions of MFC. See the MFC sample DOCKTOOL.

  • Tool Tips Now uses the tooltip control represented by class CToolTipCtrl.

  • CStatusBar Now uses the status bar control represented by class CStatusBarCtrl. Class COldStatusBar provides the previous implementation for backward compatibility so that you can continue to use your customizations from the previous version of MFC.

  • CPropertySheet and CPropertyPage Now use the Win32 property sheet API.

In addition, enhancements to class CControlBar, the base class for CToolBar, CStatusBar, and CDialogBar, let your users resize toolbars in the same way you can resize the toolbars in Visual C++ and many other Microsoft applications.

Rich Edit Classes

In addition to CRichEditCtrl, a class that encapsulates the rich edit text control, MFC supplies related classes to complement the control and enhance its use for building text editors. These new classes are listed below. The new classes integrate a rich edit control with the MFC document/view architecture.

  • CRichEditDoc Maintains a list of OLE client items and works with a CRichEditView.

  • CRichEditView Maintains the text and its formatting characteristics and works with a CRichEditDoc.

  • CRichEditCntrItem Provides container-side access to the OLE client items stored in a CRichEditDoc.

Other New Controls

Other new MFC classes provide specialized list box controls:

  • CDragListBox A list box control in which you can drag items to produce orderings other than alphabetical.

  • CCheckListBox A list box control in which the strings are preceded by check boxes. For an example, see the dialog box that opens when you choose Custom on the Installation Options dialog box in Visual C++ Setup.

New Common Dialogs

There are several new classes for common dialog boxes. OLE dialog boxes now use the OLEDLG.DLL file supplied by the system. All common dialog classes are now derived from CCommonDialog.

  • CPageSetupDialog Encapsulates the services provided by the Windows common OLE Page Setup dialog box with additional support for setting and modifying print margins. This class is designed to take the place of the Print Setup dialog box.

  • COlePropertiesDialog Encapsulates the Windows common OLE Object Properties dialog box. Common OLE Object Properties dialog boxes provide an easy way to display and modify the properties of an OLE document item in a manner consistent with Windows standards.

Ability to Easily Customize the File Open Dialog Box

Class CFileDialog includes new member functions for customizing the File Open dialog box. For example, you can add your own controls to the dialog box.

See Also Changes from MFC Versions 2.0 and 2.5, Changes from MFC Version 2.0 32-Bit Edition, Features No Longer Available in MFC


Changes from MFC Versions 4.x

  • Internet Server Classes

  • Internet Programming Support (wrappers of the new Win32 Internet (WinInet) and ActiveX control technology)

  • ODBC Feature Enhancements (including support for multithreading and bulk row fetching)

  • Remote Data Accessibility and Data Binding (controls that you can bind to local or remote data sources)

  • Support for Mouse Scroll Wheel (such as the one on the Microsoft IntelliMouse) added to CScrollView

  • Other New MFC Classes

  • Change in COleDateTime


Internet Server Classes

MFC has added five new classes that implement the Internet Server API (ISAPI). Using these classes, you can create DLLs that add functionality to Internet servers and Web pages. The new ISAPI Extension Wizard creates Internet server extensions and filters. Internet server extensions and filters are DLLs based on the new Internet server classes.

  • CHttpServer A class for creating an Internet server extension. Internet server extensions provide a more efficient, DLL-based alternative to Common Gateway Interface (CGI) applications.

  • CHttpFilter A class for creating an Internet server filter to screen messages sent to and from an Internet server.

  • CHttpServerContext A class which CHttpServer uses to handle concurrent, multiple requests.

  • CHttpFilterContext A class which CHttpFilter uses to handle concurrent, multiple requests.

  • CHtmlStream Called by CHttpServer to send an HTML (HyperText Markup Language) stream back to the client.


Internet Programming Support

Visual C++ 4.2 included new additions to MFC that wrap the Win32 Internet and APIs to provide support of the ActiveX controls and COM. It also added more articles about using MFC to create Internet server extensions and filters.

Visual C++ supports Internet programming in the following areas:

Technology | Description | Article(s)
Win32 Internet | Win32 Internet API (WinInet) makes the Internet an integral part of any application and simplifies access to the Internet services FTP, HTTP, and gopher. | Internet Programming with WinInet Internet First Steps: WinInet
Active documents | Active documents can be displayed either in the entire client window of a Web browser, such as Internet Explorer 3.0, or in an OLE container—such as the Microsoft Office Binder—that supports Active documents. | Internet First Steps: Active Documents
ActiveX controls | ActiveX controls can be used in Internet or desktop applications and require fewer resources than traditional OLE controls. These controls are lightweight, require few interfaces, and can be windowless and always in-place active. | Internet First Steps: ActiveX Controls
Asynchronous monikers | Asynchronous (URL) monikers enable your application to download files and control properties asynchronously, thus freeing system resources for other processes while the tasks are completed. This functionality is especially useful in Internet programming, where slow network access often delays processes and stalls the user interface. | Internet First Steps: Asynchronous Monikers
Expanded ISAPI documentation | The ISAPI documentation includes steps for creating a server extension or a filter, programming tips about programming an Internet server, and information on debugging a remote application. | Internet Server API (ISAPI) Extensions

To locate additional topics of interest about Internet programming, see the article Internet: Where Is....

The Win32 ActiveX SDK documentation is included on the Visual C++ version 6.0 CD-ROM. You can also download it from the World Wide Web at http://www.microsoft.com/intdev/sdk/.


ODBC Feature Enhancements

Several important changes have been made to the MFC ODBC classes:

  • MFC now provides multithreading support for the ODBC classes. Note, however, that this is limited to the thread-safety of the ODBC components and drivers. For more information, see the article ODBC Classes and Threads.

  • The MFC ODBC classes no longer use asynchronous processing. Data access operations are now synchronous. For a list of obsolete MFC ODBC member functions, see the topic Obsolete MFC Functions.

  • Class CDatabase provides improved support for transactions. Cursor preservation after a transaction commit or rollback is no longer required for transactions to be enabled. However, you must call the new member functions GetCursorCommitBehavior and GetCursorRollbackBehavior to check the effect of transactions on open recordsets. In addition, Technical Note 68 addresses issues specific to using transactions with the Microsoft Access 7 ODBC driver.

  • CDatabase has a new member function, OpenEx, for establishing a connection to a data source. The Open member function still exists; however, OpenEx is the preferred way to connect to a data source.

  • Class CRecordset offers support for bookmarks. For more information, see the article Recordset: Bookmarks and Absolute Positions (ODBC). CRecordset uses the new CDBVariant class to store bookmark values.

  • CRecordset provides support for bulk row fetching. For more information, see the article Recordset: Fetching Records in Bulk (ODBC). For an example of how to implement bulk row fetching, see the MFC sample DBFETCH.

  • CRecordset::Open provides many new options to enhance functionality.

  • CRecordset no longer contains any pure virtual functions. This means you can create a recordset object directly from CRecordset. For an example of how to do this, see the new member function CRecordset::GetFieldValue.


Remote Data Accessibility and Data Binding

In Visual C++ version 4.2 and later, MFC provides a means to bind simple and complex data controls to any ActiveX data source control, including the RemoteData Control. The new CWnd member functions GetDSCCursor, BindDefaultProperty, BindProperty, and OnDSCNotify provide this functionality.

When you bind the RemoteData Control to a remote database, you can use Remote Data Objects (RDO) to manipulate the RemoteData Control programmatically. When you insert one of these controls into your project, Visual C++ automatically creates the C++ class framework for manipulating them with RDO. For more information, see http://www.microsoft.com/visualc/v50/index.htm.

The following samples demonstrate how to use the data-bound controls with the Remote Data Control:

  • BINDENRL

  • EXTBIND

  • MDIBIND

Note If you are a Visual Basic user, you are accustomed to using the Data source control to bind controls to local databases. In Visual C++, you use the RemoteData Control, instead. The RemoteData Control provides the capability to bind controls to local databases as well as to remote databases.


Support for Mouse Scroll Wheel

Starting with Visual C++ version 5.0, CScrollView has inherent support for a mouse scroll wheel. For example, Microsoft IntelliMouse has a wheel control that allows you to scroll through documents without using scroll bars. CScrollView fully supports the mouse scroll wheel by processing WM_MOUSEWHEEL messages.


New MFC Classes

The new MFC classes since Visual C++ 4.0 include Internet server classes and other new MFC classes. These other classes are listed here:

  • CDockState A CObject class that can hold the state of a number of control bars. You can save the state to and load the state from the registry, an INI file, or the binary contents of a CArchive object.

  • CRecentFileList A CObject class that supports the most recently used (MRU) file list.

  • CSharedFile A CMemFile class that supports RAM-based shared memory files for fast temporary storage and for transferring raw bytes or serialized objects between independent processes.

Win32 Internet Programming

  • CInternetSession creates and initializes one Internet session or several simultaneous Internet sessions and, if necessary, describes the connection to a proxy server.

  • CInternetConnection manages your connection to an Internet server.

  • CInternetFile and its derived classes allow access to files on remote systems that use Internet protocols.

  • CHttpConnection manages your connection to an HTTP server.

  • CHttpFile provides the functionality to find and read files on an HTTP server.

  • CGopherFile provides the functionality to find and read files on a gopher server.

  • CFtpConnection manages your connection to an FTP server.

  • CGopherConnection manages your connection to a gopher server.

  • CFileFind performs local and Internet file searches.

  • CFtpFileFind aids in Internet file searches of FTP servers.

  • CGopherFileFind aids in Internet file searches of gopher servers.

  • CGopherLocator gets a gopher "locator" from a gopher server, determines the locator's type, and makes the locator available to CGopherFileFind.

  • CInternetException represents an exception condition related to an Internet operation.

Active Documents

  • CDocObjectServer maps the DocObject interfaces, and initializes and activates an Active document.

  • CDocObjectServerItem implements OLE server verbs specifically for Active document servers.

ActiveX Controls

  • CMonikerFile takes a moniker, or a string representation that it can make into a moniker, and binds it synchronously to the stream for which the moniker is a name.

  • CAsyncMonikerFile works similarly to CMonikerFile; however, it binds the moniker asynchronously to the stream for which the moniker is a name.

  • CDataPathProperty implements an OLE control property that can be loaded asynchronously.

  • CCachedDataPathProperty implements an OLE control property transferred asynchronously and cached in a memory file.

  • COleCmdUI allows a DocObject to receive commands that originate in its container's user interface (such as FileNew, Open, Print, and so on), and allows a container to receive commands that originate in the DocObject's user interface.

  • COleSafeArray works with arrays of arbitrary type and dimension.

  • COleControl now includes the following member functions for implementing ActiveX controls:
    ClientToParent ClipCaretRect GetActivationPolicy
    GetCapture GetClientOffset GetClientRect
    GetControlFlags GetDC GetFocus
    GetWindowlessDropTarget InvalidateRgn OnGetNaturalExtent
    OnGetViewExtent OnGetViewRect OnGetViewStatus
    OnInactiveMouseMove OnInactiveSetCursor OnQueryHitPoint
    OnQueryHitRect OnWindowlessMessage ParentToClient
    ReleaseCapture ReleaseDC ResetStockProps
    ResetVersion ScrollWindow SerializeExtent
    SerializeStockProps SerializeVersion SetCapture
    SetFocus

Database Programming

  • CDBVariant allows you to store a value without worrying about the value’s data type. CDBVariant tracks the data type of the current value, which is stored in a union.

  • CRecordset includes 17 new member functions that enhance functionality and provide support for bookmarks and bulk row fetching.
    CanBookmark CancelUpdate CheckRowsetError
    DoBulkFieldExchange FlushResultSet GetBookmark
    GetFieldValue GetODBCFieldCount GetODBCFieldInfo
    GetRowsetSize GetRowsFetched GetRowStatus
    RefreshRowset SetAbsolutePosition SetBookmark
    SetRowsetCursorPosition SetRowsetSize

  • CDatabase includes four new member related to transactions, bookmarks, and connecting to a data source:
    GetCursorCommitBehavior GetCursorRollbackBehavior
    GetBookmarkPersistence OpenEx

Data Binding

  • CWnd includes four new member functions that implement data binding functionality:
    GetDSCCursor BindDefaultProperty
    BindProperty OnDSCNotify


Change in COleDateTime

Two-digit dates are no longer valid in COleDateTime. You must specify a date of 100 or greater.

If you create a COleDateTime object with a date less than 100, the date will be accepted, but subsequent calls to GetYear, GetMonth, GetDay, GetHour, GetMinute, and GetSecond will fail and return -1.

Previously, you could use two-digit dates, but dates must be 100 or greater in Visual C++ version 4.2 or later.

To avoid problems, specify a four-digit date. For example:

COleDateTime.mytime(1996,1,1,0,0,0);


Changes from MFC Version 4.22

MFC has changed substantially since it shipped in Visual C++ Version 5.0. MFC 6.0 contains many new classes, new member functions, bug fixes, and enhancements. This document provides an overview of issues that could affect the porting of your MFC version 4.22 application to 6.0. For information on new classes and functionality for MFC 6.0, see What’s New for Visual C++ Version 6.0.

While the library has undergone some growth, you should be able to recompile your programs with the new library without any changes. Further, you should be able to install the MFC DLLs over old versions without recompiling programs which use the library. However, in some cases, changes in the library may cause problems when porting existing MFC application code. This document describes those changes which might be of interest to the developer.

  • Global Changes

  • Library Implementation Changes


Global Changes

Placement-syntax support for global operator delete()

The compiler now supports placement-syntax delete operators that properly delete memory in situations where placement-syntax operator new was used. Since MFC makes heavy use of placement-syntax new in both debug and nondebug builds, support for the placement-syntax delete operator was added.

For more information changes to various library classes, see Library Implementation Changes.


Library Implementation Changes

CAsyncSocket

The SendTo member function correctly returns errors. In previous versions of MFC, SendTo returned FALSE for some errors. The function now returns a proper WinSock error code in all circumstances.

Collection Classes

FindIndex returns NULL for negative indexes.

List-based collections with a FindIndex member will return NULL if the index passed to the function is negative. In previous releases, a negative index caused the program to stop responding or an access violation.

CControlBar

  • New SetBorders member function

    The SetBorders member is a public accessor that allows other classes to set the bar’s borders.

  • New DrawGripper member function

    The DrawGripper member function draws a "gripper," that is a user-interface clue on command bars that are movable or resizable. CalcInsideRect adjusts for the correct sizing of a bar that has a gripper.

  • New assertion behavior for m_dwStyle

    The CControlBar class will assert that the m_dwStyle member only contains MFC-specific bits—masked by CBRS_ALL. This assertion will fire if user code incorrectly sets window-style bits.

CDaoDatabase

Some recent releases of MFC had problems running correctly on machines that weren’t updated to DAO 3.5. Those problems have been resolved, but it is still advisable to upgrade to DAO 3.5, due to performance and stability improvements.

CDaoRecordset

  • Newly const members

    The IsBOF and IsEOF member functions are now const.

  • Unicode version of DFX_Text fixed

    The DFX_Text function would not allocate enough space when binding Unicode strings, and this problem has been fixed.

CDC

In previous versions of MFC, CDC member functions would sometimes return unpredictable values for extreme failure conditions. These functions have been cleaned up and now return the correct error code.

CInternetFile

ReadString doesn’t truncate

In some circumstances, the ReadString member function would truncate data read from the connection. This bug has been fixed.

CInternetSession

  • Aggressive buffer validation

    All Internet-related functions in MFC more aggressively assert on the validity of memory buffer pointer parameters.

  • No async support

    INTERNET_FLAG_ASYNC was never supported by MFC. The presence of this flag now causes debug builds of MFC to assert.

COleControl

  • Ignores fastBeginPaint

    The style bit fastBeginPaint is now ignored. ActiveX controls are always expected to erase their background in OnDraw, as they won’t receive WM_ERASEBKGND when rendering to a metafile DC.

  • Reflector window handles WM_SIZE

    The reflector window now handles WM_SIZE appropriately. Previously, the message was ignored.

COleDateTime

Member function rounding errors

Several rounding errors that existed in previous versions of the following member functions have been remedied: GetDays, GetHours, GetMinutes, GetSeconds, GetTotalDays, GetTotalHours, GetTotalMinutes, GetTotalSeconds.

COleDocument

Previous versions of MFC opened a storage with STGM_SHARE_EXCLUSIVE. MFC now uses the more appropriate STGM_SHARE_DENY_WRITE flag, which allows other applications to read the storage while it is opened by the document object.

CPropertyPage

  • Bogus assert fixed

    The creation of a property sheet with pages from a DIALOGEX resource would sometimes needlessly assert. The assertion has been corrected.

  • MapWizardResult return code

    The MapWizardResult member function would sometimes return an incorrect value. This problem has been corrected.

  • Property page activation could fail

    Some property page creations would result in a blank dialog box. This problem was fixed.

  • Incorrect return code from property page procedure

    MFC’s handler for EndDialog incorrectly returned IDCANCEL instead of PSBTN_CANCEL.

  • m_nModalResult incorrectly set

    A property page closed with the system menu or by the user pressing the close button might not correctly set the m_nModalResult member to IDCANCEL. This has been fixed.

CRecordset

The RFX_Int function incorrectly handled NULL values in previous versions of the library. This problem has been corrected.

CTabCtrl

SetItemState and GetItemState member functions have been added to support new functionality exposed by the revised COMCTL32.DLL.

CToolBar

The SetSizes function previously caused an assert when it wasn’t attached to a window, but now reacts by setting the member data of the object to reflect the size instead of moving the window’s position.

CScrollView

  • Mouse wheel asserts fixed

    A bug that caused a bogus assert when the mouse wheel was used to scroll a CScrollView has been fixed.

  • Mouse wheel page-mode scrolling fixed

    A bug that made page-by-page views scroll in the wrong direction has been fixed.

CView

The print preview bar has been restored to its rightful position—within the parent frame.

CWinThread

The MFC-supplied PreTranslateMessage member function is no longer responsible for canceling active tooltips. This code has been moved to CWnd::FilterToolTipMessage. This change was necessary to support the new tracking tooltip styles.

CWnd

The CenterWindow function has been fixed to work properly on multiple-monitor machines.


Porting and Upgrading OCXs and VBXs

Home | Overview | How Do I | FAQ | Details

As of Visual C++ 4.0, the Microsoft OLE Control Development Kit (CDK) became fully integrated with the Microsoft Foundation Class Library (MFC). For development of 32-bit ActiveX controls (formerly OLE controls), use the ActiveX Template library (ATL) or the MFC library.

You can use 16-bit controls only in 16-bit containers and 32-bit controls only in 32-bit containers. However, you can write 32-bit controls, then port them to 16 bits. (Some control features are not available in 16-bit controls.)

You can use Visual Basic controls in your Visual C++ projects, and vice versa.

To port or upgrade your ActiveX controls and Visual Basic controls, see these in-depth articles:

  • Adding an ActiveX Control to an Existing CDK Project

  • VBX Control Migration

  • Converting a CDK Project to a Visual C++ Project


Beginning Your Program

You have designed your program. Now it's time to create your Visual C++ project with its initial files and project settings. After that, you can begin adding user-interface features, adding code to implement your program's functionality, and debugging as you go.
Overview A short introduction to some important concepts to know before you begin your program.
How Do I Everything you need to know to create a Visual C++ program.
Details Detailed information about subjects of interest when you are beginning your program.
What else do you want to do?
Port my previous VC++ projects to the current version.
Learn more about the kinds of programs I can create with Visual C++.
Start creating my own program -- how do I begin?
Learn about Visual C++ wizards that will create program files to help me get started.

Interesting home pages
Visual C++ Home The entire Visual C++ product.
Adding User-Interface Features Developing the user interface and other features of your program.
Compiling and Linking Building your program.
Debugging Debugging your program.
Adding Program Functionality Developing code.


Overview: Beginning Your Program

Home | How Do I | Details

The Beginning Your Program topics in the Visual C++ Programmer’s Guide cover ways to begin writing Windows programs in C++ using Microsoft Wizards, the Microsoft Foundation Classes (MFC) and the Active Template Library (ATL). Wizards, like the MFC AppWizard, the MFC ActiveX ControlWizard, the ISAPI Extension Wizard, and the ATL COM AppWizard help you generate the basic source files for a variety of different types of Windows programs. The MFC and ATL libraries provide prewritten classes, as well as supporting code, that you can add to your source files to handle the Windows programming tasks specific to the logic of your program.

Using Wizards and the MFC and ATL libraries, you benefit not only from the pre-written code they provide, but also from the pre-generated source code that uses calls to the MFC and the ATL and handles many routine programming tasks. You can, of course, write a program without using a Wizard, but the Wizards save you so much time it doesn’t make sense not to use them.

These topics also cover ways to begin writing Windows programs in C or C++, using calls to the Win32 API rather than to MFC classes. Wizards aren’t available for these older style programs but Visual C++ still helps you get going by providing some starter files for your program.

The following general and more specific topics provide links to overview information that will help you begin your Visual C++ program.

General Overviews

These topics describe the types of programs you can create, how to organize your Visual C++ program into a project in a workspace, and how to use the Visual C++ Wizards.

What do you want to know more about?

  • Creating a Visual C++ program

  • What is a Visual C++ project and how does it relate to a workspace?

  • Wizards for creating projects

Beginning Your Program Overviews

These topics contain overview information about creating specific types of programs.

What kind of Visual C++ program do you want to know more about creating?

  • An MFC program

  • An MFC DLL

  • An MFC ActiveX control program

  • An ActiveX Container program

  • An Internet Server (ISAPI) Extension or Filter

  • A Win32 (non-MFC) program for Windows

  • A Win32 DLL

  • A Static Library

  • A Console program

  • A Utility Project

  • A program that supports a DAO or ODBC database

  • An Extended Stored Procedure

  • A Microsoft Cluster Resource Type

What other kinds of programs do you want to know more about?

  • External Makefiles

  • Add-in programs

  • MFC sample programs

  • A program that uses the ATL COM Template Library


Creating a Visual C++ Program

Home | Overview | How Do I | Details

You will be using the integrated development environment for creating all of your Visual C++ programs. The environment provides a broad set of development tools for completing, testing and refining your program. For example, the development environment includes a text editor, resource editors, build options, an optimizing compiler, an incremental linker, a source code browse window, and an integrated debugger.

The files you create for your C++ program will be organized into a Visual C++ project in a workspace. When creating Visual C++ programs that use the Microsoft Foundation Classes (MFC) or the Active Template Library (ATL), Win32 programs or libraries a wizard will help you create the C++ project files and some starter source files for your program.

Note If the program you are creating uses MFC, you want to work with a practice program before actually beginning your program. Several MFC Class Library Tutorials are available to help you learn more about creating a program.

What do you want to know more about?

  • The specific type of program I am creating

  • What is a Visual C++ project and how does it relate to a workspace?

  • How to use an existing makefile not created in the development enviroment

  • MFC sample programs


What is a Visual C++ Project?

Home | Overview | How Do I | Details

Your Visual C++ program is organized into a Visual C++-based project that contains all the files you use when developing, compiling, building, and debugging your application. You view your project in a workspace window which has four different tabs for displaying information: ClassView, which shows the classes in your project, FileView, which shows the files in your project, and ResourceView, which shows the resources in your project.

Visual C++ projects are part of a project workspace that allows you to create multiple projects in more than one language in a shared development environment. Files created in one Visual C++ project can be shared with other Visual C++ projects and, where appropriate, with projects created for other programs.

When your Visual C++ programs use the Microsoft Foundation Classes (MFC) or the Active Template Library (ATL), wizards create starter files for you. When you create non-MFC programs or libraries, a project file is created and then you add your source files to it.

What do you want to know more about?

  • Working with projects

  • Can I use a wizard to create my project?

  • What MFC Class Library Tutorials are available to help me learn more about creating a program?


Visual C++ Wizards that Help You Begin Your Program

Home | Overview | How Do I | Details

Visual C++ provides wizards that work in conjunction with the MFC application framework and the Active Template Library to create starter programs for you. Other wizards help you add functionality to your Visual C++ programs.

Some Visual C++ Wizards That Help You Begin Your Program

MFC AppWizard Generates a complete suite of source files and resource files based on classes from the MFC library. The are two versions of this wizard, one that helps you create an MFC executable program and one that helps you create an MFC DLL. By selecting options in AppWizard, you can customize the starter files that AppWizard generates. Once you have completed the steps in AppWizard, Visual C++ creates a functional starter application for Windows from the starter files, without any further work on your part.

MFC ActiveX ControlWizard This wizard helps you create an ActiveX (formerly OLE) control. Once you have completed the steps in ControlWizard, Visual C++ creates all the files necessary to create an ActiveX control, including source and header files, resource files, a module-definition file, a project file, an object description language file, and so on. You can then use ClassWizard to define your control’s events, properties, and methods, some of which have been preimplemented in the MFC library.

The ISAPI Extension Wizard This wizard helps you create an Internet Server API Extension or Filter. Once you have completed the steps of this wizard, Visual C++ creates all the files necessary to create an Internet Server or Filter DLL.

The ATL COM AppWizard Walks you through the tasks associated with creating an Active Template Library (ATL) application. Depending on the Wizard options you choose, these applications can be very small and efficient.

Custom AppWizard When you create a Custom AppWizard you can create your own project type and add it to the list of types available when you create projects. It creates the starter source files for the new AppWizard type, and allows you to modify or add dialog boxes to your AppWizard. Custom AppWizards are useful for creating generic application project types that can repetitively generate common functionality—application types that can be used over and over again.

Other Wizard Topics

ClassWizard Like a programmer’s assistant, ClassWizard makes it easier for you to do certain routine tasks such as creating new classes, defining message handlers, overriding virtual functions, and gathering data from controls in a dialog box, form view, or record view. ClassWizard also makes it easy to add properties, methods, and events to automation objects. ClassWizard works with programs that use the Micrososft Foundation Class Library (MFC) or the Active Template Library (ATL).

WizardBar A tool that simplifies routine tasks such as defining message handlers, overriding MFC virtual functions, and navigating in an implementation (.CPP) file. Like ClassWizard, WizardBar works works with programs that use the Micrososft Foundation Class Library (MFC) or the Active Template Library (ATL).

The Add-in Wizard Helps you create add-ins designed to automate tasks. Add-ins are in-process COM components (DLLs) written in Visual C++ or Visual Basic.

Other Wizards Click here for a list of the wizards for all the development packages you have installed.

What program do you want to use a wizard to create?

  • An MFC program

  • An MFC DLL

  • An MFC ActiveX Control program

  • A Win 32 (non-MFC) program

  • A Win32 Dynamic-Link Library (non-MFC)

  • A static library

  • A console program

  • A Utility Project

  • A makefile

  • An Internet Server (ISAPI) extension or filter

  • A program that supports a DAO or ODBC database

  • A program that uses the ATL COM Template Library

  • Add-in programs

  • An Extended Stored Procedure

  • A Microsoft Cluster Resource Type

What do you want to know more about?

  • How to create an ActiveX or OLE Container Program

  • What MFC Class Library Tutorials are available to help me learn more about creating a program?


How Do I Begin My Visual C++ Program?

Home | Overview | Details

To create a new Visual C++ program

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the type of project you want to create.

    If you are creating an MFC-based project, double-click the icon for MFC AppWizard (exe), MFC AppWizard (dll) , MFC ActiveX ControlWizard, ATL COM AppWizard or ISAPI Extension Wizard. The Wizard will guide you through a series of questions on the features that you want to include in your program. It will also create a set of workspace, project, and MFC starter files and a dependency checker for your program.

    If you are creating a static library, console program, makefile or non-MFC application project, double-click the appropriate icon. Workspace and project files and a dependency checker are automatically generated for your program.

Notes For more detailed information about creating each type of program, click a topic in the list below. If the program you are creating uses MFC, you may want to work with a practice program before actually beginning your program. Several MFC Class Library Tutorials are available to help you learn more about creating a program.

What program do you want to create?

MFC Programs and DLLs

  • An MFC Program

  • An MFC Dynamic-Link Library (DLL)

  • An Internet Server (ISAPI) Extension

ActiveX Controls or Programs

  • An MFC ActiveX Control Program

  • An ActiveX Container Program

  • A program that uses the ATL COM Template Library

Other Kinds of Programs

  • A non-MFC Win32 executable program

  • A Win32 Dynamic-Link Library (DLL)

  • A static library

  • A console program

  • A Utility Project

  • A program that supports a DAO or ODBC database

  • Wrap an existing project (external makefile)

  • An Extended Stored Procedure

  • A Microsoft Cluster Resource Type


Overview: Creating an MFC EXE Program

Home | Overview | How Do I | Details | Sample

An MFC program is an executable application for Windows that is based on the Microsoft Foundation Class (MFC) Library. When you use the MFC AppWizard to create an MFC program, you get a working starter program. This program has built-in functionality that when compiled, will implement the basic features of a Windows executable (.EXE) program. The MFC starter program will include C++ source (.CPP) files, resource (.RC) files, header (.H) files, and a project (.DSP) file. The code generated in these starter files is based on MFC.

There are three steps to creating an MFC EXE program. First, following the steps and choosing the options provided by the MFC AppWizard, define the features of your program. Next, compile and link the starter program. Finally, using WizardBar, you can add code to the starter files that AppWizard created.

What do you want to do?

  • Create an MFC EXE program with AppWizard

  • Create an MFC DLL

  • Learn more about MFC

  • Learn more about the MFC AppWizard

  • Learn about AppWizard language support for Far East languages

  • See what MFC Class Library Tutorials are available to help me learn more about creating an MFC program

  • Learn about using classes to write programs


Create an MFC EXE Program with AppWizard

Home | Overview | Details | Sample

When you first create an MFC executable program, you use the MFC AppWizard (EXE version) to lead you through a series of dialog boxes in which you choose options for the architecture, features, and functions of your project.

The series is a branching path: you can move forward and backward through the steps and make changes to the options you have selected. Help is available for every option in the MFC AppWizard: right-click on the control for more information about each option.

To create an MFC EXE program using AppWizard

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the MFC AppWizard (exe) icon.

  3. Complete the steps of the MFC AppWizard by choosing the appropriate options for your program. Click here for a step-by-step explanation of the MFC AppWizard.

  4. Prepare your MFC program for use. Click here for more information.

What do want to know more about?

  • AppWizard language support for Far East languages

  • Creating a Forms-Based Application

  • Creating an Explorer-Style Application

  • Creating a Web-Browser-Style Application


The MFC AppWizard (EXE version): Step-by-Step

Home | Overview | How Do I | Details | Sample

The MFC AppWizard series is a branching path of either 4 or 6 steps depending on the architecture you select for your program. You can move forward and backward through the steps and make changes to the options you have selected.

Help is available for every option in each step: right-click on the control for more information about each option.

To complete Step 1

  1. Choose one of three architectures for your program: Single Document (SDI), Multiple Document (MDI), or Dialog Based.

  2. Decide if you want your application to support MFC's document/view architecture. An application without document/view architecture would not have MFC support to open a document from a disk file and the window area is derived from CWnd. See Alternatives to the Document/View Architecture.

    If you choose not to use document/view architecture, other options in Steps 2-5 will not be available.

  3. Select a language for the resource text and then click Next.

  4. If you selected a dialog-based architecture, click here for Step 2.

To complete Step 2 for an SDI or MDI type program

  1. Choose one of four database support options for your program: None, Header file support, Database View (with file support) or Database View (without file support).

  2. If you selected database view support, click Data Source and choose either an external ODBC database, DAO database or OLE DB database and the appropriate data source and Database Table options.

    For more information, see Data Source (ODBC), DAO External: Working with External Data Sources, Using the OLE DB Consumer Templates

  3. Click Next.

To complete Step 3 for an SDI or MDI type program

Choose the compound document support you would like to include in your program:

Container

An OLE 2.0-style document container.

Mini-server

An OLE server that cannot run as a standalone program.

Full-server

An OLE server that can also run as a standalone program.

Active Document Servers

Active Document Containers

Also, select options to enable the standard ActiveX resources and to add extra Automation commands to the application's menu bar.

To complete Step 4 for an SDI or MDI type program

  1. Choose which basic user-interface features you want your program to have and the type of toolbars to use: IE4.0 ReBars or MFC (command) toolbars. See Windows Sockets in MFC and MAPI Support in MFC for more information.

  2. If you want to modify the filenames and extensions that your program uses or want to adjust the user interface window frame styles for your program, click Advanced.

  3. Click Next.

To complete Step 5 for an SDI or MDI type program

  1. Choose the project style: Explorer, which gives you a tree view on the left and a list view on the right or MFC Standard, which gives you one area for a file view.

  2. Choose whether or not you would like AppWizard to generate comments in the source file that will guide you in writing your program.

  3. Choose whether you would like to use the MFC library as a shared or statically linked DLL.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

To complete Step 6 for an SDI or MDI type program

  1. If you want to change the default class name, base class, header or implementation file names provided by AppWizard, enter the new names. To change the Base class, select your program's view class (see Derived View Classes).

  2. Click Finish and then click here to prepare your MFC program for use.

To complete Step 2 for a dialog-based program

  1. Choose which basic user-interface features you want your program to have and what WOSA support to include. See Windows Sockets in MFC for more information.

  2. Click Next.

To complete Step 3 for a dialog-based program

  1. Choose Yes, if you would like comments about where you need to add your own code into the source file.

  2. Choose whether you would like to use the MFC library as a shared or statically linked DLL.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

To complete Step 4 for a dialog-based program

  1. If you want to change the default class name, header or implementation file names provided by AppWizard, enter the new names. To change the Header or Implementation file name, select your program's dialog class.

  2. Click Finish and then click here to prepare your MFC program for use.


Creating a Forms-Based Application

Home | Overview | How Do I | Details | Sample

A form is dialog box with controls that let a user access and possibly change data. You may want to develop an application in which the user chooses from a selection of forms. Commonly, a forms-based application lets the user access forms by selecting New from the File menu. A dialog-based application, which does not give users access to a New option in the File menu, is also considered a forms-based application.

To create a forms-based application:

  • In Step 1 of the MFC AppWizard, select the Document/View architecture support? check box.

  • Also in Step 1 of the wizard, select Single document, Multiple documents, or Dialog based. A single document interface, forms-based application only allows one instance of a particular form to run at a time. However, it is possible to run different forms at the same time from an SDI, forms-based application by selecting a new form from the New option in the File menu.

    If you create an MDI, forms-based application, the program will be able to support multiple instances of the same form.

    An SDI or MDI forms-based application both use the document/view architecture.

    Any dialog-based application, by definition, is forms based. However, you will not be able to add additional forms to the dialog-based application via the New Form option in the Insert menu. Because a dialog-based application does not use the document/view architecture, you will have to manage the creation and access methods for your own additional forms.

  • In Step 6 of the wizard and if you chose a single document or multiple document interface application in Step 1, select CFormView as the base class for your application's View. If your application has database support, you can also select any class that derives from CFormView. A form is any window derived from CFormView or from any class that inherits from CFormView.

    Even if you choose a base class such as CView, you can later make your applications forms-based by adding forms with the New Form option of the Insert menu.

After you finish with the wizard, your project will open and if you selected CFormView (or a class that inherits from CFormView) as your base class, Visual C++ will open the dialog editor and you will be ready to design your first form.

See Also Form Topics.


Creating an Explorer-Style Application

Home | Overview | How Do I | Details | Sample

Many Windows system applications use the Windows Explorer user interface (UI). When you start Windows Explorer, for example, you see an application with a vertical bar dividing the client area. The left side of the client area makes navigation and browsing possible, while the right side of the client area shows details pertinent to the selection in the left pane. When you click an item in the left pane, the application repopulates the right pane. You can use commands on the View menu to change the amount of detail shown in the right pane.

You use Windows Explorer to navigate the computer file system. The left pane shows a hierarchical view of directories, computers, or computer groups, while the right pane shows individual files or computers and their subordinate directories and files.

You can have AppWizard produce an Explorer-style application for you by selecting the "Explorer Style" button in Step 5 of the AppWizard.

The generated application resembles either a single document interface application or a multiple document interface application. AppWizard will generate code so that each frame window created by the application has a horizontal bar using a CSplitterWnd. The left pane will always contain a tree view control. You can use Step 6 of the AppWizard to adjust the type of view used to display detail for the selected item in the application.

If you use the AppWizard default list view in the right pane, the Wizard creates additional menu choices and toolbar buttons to switch the view's style among report mode, small icon mode, and list mode.

Coding this application type is similar to coding a normal MFC application that uses a splitter; however, the AppWizard has provided code that creates control views within the splitter panes.


Creating a Web browser-style Application

Home | Overview | How Do I | Details | Sample

You can use the MFC AppWizard to create an application that displays any Web content you specify.

To create a Web browser application

  1. Follow the steps to create an MFC AppWizard (.exe version).

    Your application must be based on the MFC document/view architecture (default).

  2. In Step 6 of the wizard, use the Base class drop-down list to select CHtmlView.

  3. Click Finish.

The CHtmlView class acts as a wrapper for the Web browser control, which gives your application a view onto a Web, or HTML page. The wizard creates an override to the OnInitialUpdate function in the view class, providing a navigational link to the Microsoft Visual C++ Web site:

void CWebView::OnInitialUpdate()
{
   CHtmlView::OnInitialUpdate();

   // TODO: This code navigates to a popular spot on the web.
   //  change the code to go where you'd like.
   Navigate2(_T("http://www.microsoft.com/visualc/"),NULL,NULL);
}

You can replace this site with one of your own, or you can use the LoadFromResource function to open an HTML page that resides in the project's resource script as the default content for the view. For example:

void CWebView::OnInitialUpdate()
{
   CHtmlView::OnInitialUpdate();

   // TODO: This code navigates to a popular spot on the web.
   //  change the code to go where you'd like.
   LoadFromResource(IDR_HTML1);
}

What do you want to know more about?

Navigate2 method

LoadFromResource function

CHtmlView class

What do you want to do?

Open my HTML page as the default in my Web Browser application

Create a New HTML Resource

Import an existing HTML file as a resource


Prepare the MFC EXE Program For Use

Home | Overview | How Do I | Details | Sample

To prepare an MFC program for use

  1. Compile and link the MFC starter files.

  2. Add code to MFC AppWizard starter files.

What do you want to know more about?

  • Compiling and Linking


Add Code to the MFC EXE Starter Files

Home | Overview | How Do I | Details | Sample

After using AppWizard to create an MFC program, you get a working starter application with whatever functionality you asked for when completing the steps in AppWizard.

Your compiled program now implements the basic features of a Windows executable (.EXE) application. Your final step is to supply the application-specific source code and connect the components by defining what messages and commands the starter files should respond to.

The easiest way to add functions and navigate to them in your starter files is either by using ClassWizard or WizardBar. You can also insert components from the Gallery that will add code to your project.

If you chose the option to generate source file comments, the MFC AppWizard creates a file called ReadMe.txt in your project directory that contains a complete listing and description of all the files that it has created. The newly created starter files will display comments in green when viewed in the project workspace. The comments indicate where to add your source code, and help define the class behaviors for your specific application.

Note In the source code, look for the comment: // TODO: add . . . code here, which explains where to add code; the comments also explain where not to edit specific blocks of code.

Example of where to add your code

// CApp3xeDoc construction/destruction
CApp3xeDoc::CApp3xeDoc()
{
   // TODO: add one-time construction code here
}
CApp3xeDoc::~CApp3xeDoc()
{
}

What do you want to know more about?

  • Getting started with MFC

  • Files created when you create a new program

  • The build settings generated by AppWizard for an MFC EXE program

  • Updating Dependencies in a Project

  • What if my MFC program build fails?

  • Where is WinMain in the starter code?


Where is WinMain in the Starter Code?

Home | Overview | Details

The WinMain function is supplied by the class library and is called when the application starts up. Class CWinApp encapsulates the initialization, running, and termination of an application for Windows. For more information, see CWinApp: The Application Class.


What if My MFC EXE Project Build Fails?

Home | Overview | How Do I | Details

If your build fails:

  • MFC provides diagnostic services you can use to debug your program.

  • MFC General Object Diagnostics include diagnostic dump context which is useful for diagnostic printing of internal object data.

What do you want to know more about?

  • The build settings generated by AppWizard for an MFC EXE program

  • Building the active project configuration

  • Compiling and linking your project


Overview: Creating an MFC DLL

Home | Overview | How Do I | Details | Sample

An MFC .DLL is a binary file that acts as a shared library of functions that can be used simultaneously by multiple applications. When you use the MFC AppWizard (DLL version) to create an MFC DLL, you get a working starter application with built-in functionality that when compiled, will implement the basic features of a DLL. The MFC starter program will include C++ source (.CPP) files, resource (.RC) files, and a project (.DSP) file. The code generated in these starter files is based on MFC.

There are three steps to this process. First, following the steps and choosing the options provided by the MFC AppWizard (DLL version), you define the features of your program. Next, you compile and link the starter program. Finally, you add code to the starter files that AppWizard created.

What do you want to do?

  • Create an MFC DLL using AppWizard

  • Learn about AppWizard language support for Far East languages

  • Learn more about DLLs

  • Export from a DLL

  • Link an executable to a DLL

  • Initialize a DLL

  • Create a Win32 DLL

  • See what MFC Class Library Tutorials are available to help me learn more about creating an MFC program

  • Learn about using classes to write programs


Create an MFC DLL with AppWizard

Home | Overview | Details | Sample

When you first create an MFC DLL, you use the MFC AppWizard (DLL version) to lead you through a series of dialog boxes in which you choose options for the architecture, features, and functions of your project.

The series is a branching path: you can move forward and backward through the steps and make changes to the options you have selected. Help is available for every option in the MFC AppWizard: right-click on the control for more information about each option.

To create an MFC DLL using AppWizard

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the MFC AppWizard (dll) icon.

  3. Complete the steps of the MFC AppWizard by choosing the appropriate options for your program. Click here for a step-by-step explanation of the MFC AppWizard.

  4. Prepare your MFC program for use. Click here for more information.

Note On the General tab of the Project Settings dialog box, you can alter your choice to use MFC in a shared DLL or in a static library. However, extension DLLs are designed to be used with the shared DLL version of MFC, and you should not change this setting for extension DLLs.

What do you want to know more about?

  • DLLs

  • The different kinds of DLLs available with Visual C++

  • Files created when you create a new program

  • Build settings generated for MFC DLLs

  • Classes and functions AppWizard generates for MFC DLLs

  • AppWizard language support for Far East languages

  • Updating dependencies in a project


The MFC AppWizard (DLL version): Step-by-Step

Home | Overview | How Do I | Details | Sample

The MFC AppWizard (DLL version) series has only one step. You can also move backward to change your project options.

Help is available for every option in the MFC AppWizard (DLL version). Right-click on the control for more information about each option.

To complete Step 1

  1. Choose what type of DLL you would like to create.

  2. Choose the Automation and/or Windows Sockets features you would like to include in your DLL.

  3. Choose Yes if you would like AppWizard to generate comments in the source file that will guide you in writing your program.

  4. Click Finish and then click here to prepare your MFC program for use.

What do you want to know more about?

  • DLLs

  • Automation

  • Windows Sockets

  • Classes and functions AppWizard generates for MFC DLLs

  • Build settings generated by AppWizard for MFC DLLs

  • Files created when you create a new program

  • AppWizard language support for Far East languages


Classes and Functions AppWizard Generates for MFC DLLs

Home | Overview | How Do I | Details | Sample

The code that the MFC AppWizard (DLL version) generates depends on the kind of DLL you are creating and the options you have selected. AppWizard generates the same code for both forms of Regular DLLs. The following table lists the classes and functions that AppWizard provides for you.

Kind of DLL | Option | Classes | Functions
Extension | None | None | DllMain
Regular | None | Application class derived from CWinApp | None
Extension | Automation | None | DllMain
Regular | Automation | Application class derived from CWinApp | DllGetClassObject DllCanUnloadNow DllRegisterServer
Extension | Window Sockets | None | DllMain
Regular | Window Sockets | Application class derived from CWinApp | InitInstance contains call to AfxSocketInit

What do you want to know more about?

  • DLLs

  • ActiveX or Automation in a DLL

  • Windows Sockets

  • AppWizard options available for MFC DLLs

  • Build settings generated by AppWizard for MFC DLLs

  • Files created when you create a new program


Prepare the MFC DLL for Use

Home | Overview | How Do I | Details | Sample

To prepare the MFC DLL for use

  1. Add code to the starter code generated by AppWizard.

  2. Make sure you have exported the entry points to your DLL by using either the __declspec(dllexport) keyword or by listing the functions in the DLL’s .DEF file. If exporting C++ classes, you may want to use the AFX_EXT_CLASS macro.

  3. Prepare a header (.H) file to include in the programs using your DLL. This header file must contain the declarations of the exported functions and/or exported C++ classes. Use the __declspec(dllimport) keyword on the declarations of the exported functions and C++ classes in this header file. The compiler produces more efficient code with __declspec(dllimport). See Technote 33 on exporting functions and classes from an MFC DLL.

  4. Build the DLL.

  5. If applications will be linking to your DLL implicitly, provide an import library for the applications to link to.

When you build your DLL, the linker also builds an import library for you. This library has the same base name as your DLL, but has the extension .LIB. You may want to provide both a debug and retail (/release) version of your DLL. This permits client programs to build both debug and retail versions of their applications and link them with the appropriate debug or retail version of all DLLs.

If you are building an application that implicitly links to a DLL, add the import library to the Object/library modules text box on the Link tab in the Project Settings dialog box. Make sure you put the debug version of the import library in the debug settings and the release version in the release settings. The only other change you must make is to add the include file for the DLL to any source files that call the DLL’s exported functions.

What do you want to do?

  • Add code to the AppWizard’s starter files for MFC DLLs

  • Learn more about DLLs

  • Export from a DLL

  • Link an executable to a DLL

  • Initialize a DLL

  • Learn how to build my program

  • Learn about updating dependencies in a project


Add Code to the MFC DLL Starter Files

Home | Overview | How Do I | Details | Sample

If your DLL needs initialization or termination code, where you add that code depends on the kind of DLL that you have created.

For extension DLLs, the .CPP file that AppWizard creates contains the function DllMain. Any initialization or termination code for your DLL should be added to this function.

For regular DLLs, initialization code should be added to the InitInstance member function of the application-derived CWinApp class. Termination code should be added to ExitInstance.

Add the rest of your code to either the .CPP file created by AppWizard or create new source files and add them to the project. Make sure you have exported the entry points to your DLL by using either the keyword __declspec(dllexport) or by listing the functions in the DLL’s .DEF file. If exporting C++ classes, you may want to use the AFX_EXT_CLASS macro.

The easiest way to add functions and navigate to them in your starter files is by using either ClassWizard or WizardBar.

What do you want to do?

  • Learn more about DLLs

  • Export from a DLL

  • Link an executable to a DLL

  • Initialize a DLL


Test the MFC DLL

Home | Overview | How Do I | Details | Sample

To test your MFC DLL, you must have a program that uses the exported classes or calls the exported functions. Click here for suggestions on managing the project workspace for the calling application and the DLL.

To debug a DLL, you must select the program that calls your DLL by clicking the Settings command on the Project menu. In the Project Settings dialog box, click the Debug tab. In the Executable for debug session box, specify which application to run while debugging.

What do you want to do?

  • Learn more about DLLs

  • Learn more about debugging DLLs


Overview: Creating an MFC ActiveX Control Program

Home | Overview | How Do I | Details | Sample

ActiveX (formerly OLE) Control programs are modular programs designed to give a specific type of functionality to a parent application. For example, you can create a control such as a button in a dialog or toolbar or on a Web page.

When you use the MFC ActiveX ControlWizard to create an MFC ActiveX Control program, you get a working starter application with built-in functionality that when compiled, will implement the basic features of an ActiveX Control. The starter program will include C++ source (.CPP) files, header (.H) files, and any optional files such as a type library source file (.ODL), a license validation file (.LIC), a Help Source file (.RTF) and so on, that you selected during setup. The code generated in these starter files is based on MFC.

There are three steps to this process. First, following the steps and choosing the options provided by the MFC ActiveX ControlWizard, you define the features of your program. Next, you compile and link the starter program. Finally, you add code to the starter files that the MFC ActiveX ControlWizard created.

What do you want to do?

  • Learn more about ActiveX Controls

  • Create an MFC ActiveX control

  • Create an ActiveX control container

  • Learn about the Active Template Library (ATL)

  • See what MFC Class Library Tutorials are available to help me learn more about creating an ActiveX control


Create a Program with the MFC ActiveX ControlWizard

Home | Overview | Details | Sample

When you first create an ActiveX (formerly OLE) Control Program, you use the MFC ActiveX ControlWizard to lead you through a series of dialog boxes in which you choose options for the features and functions of your program.

The series is a branching path; you can move forward and backward through the steps and make changes to the options you have selected. Help is available for every option in the MFC ActiveX ControlWizard: right-click on the control for more information about each option.

To create an MFC ActiveX Control program

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the MFC ActiveX ControlWizard icon.

  3. Complete the steps of the MFC ActiveX ControlWizard by choosing the appropriate options for your program. Click here for a step-by-step explanation of the MFC ActiveX Control Wizard.

  4. Prepare your ActiveX Control for use. Click here for more details.


The MFC ActiveX ControlWizard: Step-by-Step

Home | Overview | Details | Sample

The MFC ActiveX ControlWizard series has 2 steps. You can move forward and backward through the steps and make changes to the options you have selected.

Help is available for every option in each step: right-click on the control for more information about each option.

To complete Step 1

  1. Choose the number of controls you would like your project to have. ControlWizard can generate up to 99 separate controls per project. Each control has a control class and a property page class.

  2. Choose whether or not you want the controls in your project to have a run-time license.

  3. Choose whether or not you would like the MFC ActiveX ControlWizard to generate comments in the source file that will guide you in writing your program.

  4. Choose whether or not you want the MFC ActiveX ControlWizard to generate help files that are used to provide context-sensitive Help. Help support requires using the Help compiler, which is provided with Visual C++.

To complete Step 2

  1. If you added more than one control to your project and you want to edit the names of the classes or files they use, select the control you want to edit from the list and click Edit Names. Repeat this procedure for each control you want to edit.

  2. Select the features you would like each control to have.

  3. Select which window class, if any, you want for each control.

  4. Click Advanced to add windowless activation, mouse pointer notifications, optimized drawing code, or asynchronous loading properties to each control.

  5. Click Finish and then click here to prepare your ActiveX control for use.

Note ControlWizard creates a bitmap that you can use on a toolbar or in the toolbox in Visual Basic, where Visual Basic programmers can use your control on their forms. See Toolbars for more information.


Prepare Your MFC ActiveX Control Program for Use

Home | Overview | Details | Sample

To prepare an MFC ActiveX Control program for use

  1. Compile and link the ActiveX (formerly OLE) Control starter files.

  2. Add code to the MFC ActiveX ControlWizard starter files.

Note The build process automatically registers an ActiveX control in the registry. But you can use the following procedure to manually register an ActiveX control in the registry if needed.

To manually register an MFC ActiveX Control

  1. On the Tools menu, click Register Control.

Registering a control adds the following information to the Registration Database:

  • The text name of the control

  • The class name of the control

  • An indicator stating that the control conforms to the MFC ActiveX control protocols

  • The path of the control’s executable

  • The path and resource ID of the control palette bitmap

  • An indication of whether the control is insertable

  • The IDispatch IDs of the control’s properties and events interfaces

Controls built with the MFC ActiveX control classes are self-registering because two entry points in the control’s executable, DLLRegisterServer and DLLUnregisterServer, are automatically added when ControlWizard creates the control’s files. As their names imply, DLLRegisterServer and DLLUnregisterServer respectively add and remove the control’s registration information in the registry.

What do you want to know more about?

  • Compiling and linking

  • Build settings generated when you create a new program

  • Files created when you create a new program

  • Updating dependencies in a project


Add Code to the MFC ActiveX Control Starter Files

Home | Overview | Details | Sample

After using the MFC ActiveX ControlWizard to create an ActiveX (formerly OLE) Control project, you get a working starter program with whatever functionality you asked for when completing the steps in the ControlWizard.

This starter program includes all the files necessary to build the control, including source (.CPP) and header files (.H), resource files (.RC), a module-definition file (.DEF), a project file (.DSP), an object description language file (.ODL), and so on. These files are compatible with ClassWizard, and you can then use ClassWizard to define the control’s events, properties, and methods, some of which have been already implemented in MFC.

Your project files contain a large amount of built-in functionality. This functionality includes code to draw the control, serialize data, and define dispatch, event, and message maps that you expand later in the development cycle.

Your final step is to supply the application-specific source code and connect the control to a parent program by defining what messages and commands the starter files should respond to. If you don’t already have a parent application, you can create an ActiveX control container using AppWizard.

If you selected the comments option when creating your program, the newly created starter files will display comments in green when viewed in the project workspace. The comments indicate where to add your source code, and help define the class behaviors for your specific control.

Note In the source code look for the comment: // TODO: , which is followed by an explanation of what to do. The comments also explain where not to edit specific blocks of code.

Example of where to add your code

CTestControl::CTestControl()
{
   InitializeIIDs(&IID_DTest, &IID_DTestEvents);
   //TODO: Initialize your control's instance data here.
}

CTestControl::~CTestControl()
{
   //TODO: Cleanup your control's instance data here.
}

What do you want to know more about?

  • Creating an ActiveX Container program

  • Build settings generated when you create a new program

  • Files created when you create a new program

  • Updating Dependencies in a Project


Frequently Asked Questions About ActiveX Controls

Home | Overview | How Do I | Details

Can I create an MFC ActiveX control by subclassing a Windows common control?

Can I make an MFC ActiveX control without a user interface?

Can I make an MFC ActiveX control with a complex user interface?


Can I Create an ActiveX Control by Subclassing a Windows Common Control?

Home | Overview | How Do I | Details | Sample

Yes, you can.

For more information, see ActiveX Controls: Subclassing a Windows Control.


Can I Make an ActiveX Control Without a User Interface?

Home | Overview | How Do I | Details

Yes, you can.

Why would you want an invisible control? In most cases, Active X (formerly OLE) controls probably should be visible, since they are meant for user interaction. If you simply want a component that can fire events to a container but you want it to be invisible, consider writing an Automation server with event support. A timer control is an example of an ActiveX control you would want to be invisible. See Automation Servers.

For further discussion, see Chapter 10 of Adam Denning's book OLE Controls Inside Out (Microsoft Press, 1995).


Can I Make an ActiveX Control With a Complex User Interface?

Home | Overview | How Do I | Details

Yes, you can.

Does an ActiveX (formerly OLE) control have to be just one control object, such as a list box or text box? No, some controls might be like encapsulated forms — a single control containing many fields, each a Windows control in its own right. For example, an auto parts object implemented as an MFC ActiveX control might present a form-like interface through which users could read and edit the part number, part name, and other information.

For further discussion, see Chapter 10 of Adam Denning's book OLE Controls Inside Out (Microsoft Press, 1995).


Overview: Creating an ActiveX Control Container

Home | Overview | Details | Sample

An ActiveX Control Container is a parent program that supplies the environment for an ActiveX (formerly OLE) control to run. You can create an application capable of containing ActiveX controls with or without MFC, but it is much easier to do so with MFC.

Creating an MFC container program using the MFC AppWizard allows you to access the many features of ActiveX controls and Automation that are implemented by the MFC and ActiveX classes. These features include visual editing, Automation, creating compound files, and support for controls. The MFC AppWizard visual editing options that your parent program will support include creating a container, a mini-server, a full-server, and a program that is both a container and a server.

There are three types of applications you can create an ActiveX container for:

  • New MFC Application. To create a new MFC program that includes Automation, visual editing, compound files, and/or control support, use the MFC AppWizard (EXE version) and in Step 3 choose the appropriate Automation options.

  • Existing MFC Application. If you are adding control containment to an existing MFC application, see OLE Control Containers: Manually Enabling OLE Control Containment.

  • Non-MFC Application. If you are adding control containment to a non-MFC application, see Control Containers in Chapter 19 of Adam Denning's book OLE Controls Inside Out (Microsoft Press 1995).

What do you want to know more about?

  • Containers

  • Visual editing

  • Controls

  • ActiveX controls

The MFC Class Library Tutorials that are available to help me learn more about creating a container program


Overview: Creating an Internet Server Extension (ISAPI) or Filter DLL

Home | Overview | How Do I | Details | Sample

If your Internet Server software is ISAPI-compliant, you can create Internet Server Extensions and Filters with MFC. An Internet Server Extension is a DLL that is used to enhance the capabilities of an Internet Server API-compliant (ISAPI) Web server. ISAPI Extensions provide an alternative to writing CGI (Common Gateway Interface) applications. An Internet Server Filter is a DLL that runs on ISAPI-enabled servers to filter data traveling to and from the server.

When you use the ISAPI Wizard to create an MFC DLL program, you get a working starter application with built-in functionality that when compiled, will implement the basic features of a Dynamic Link Library (DLL) program. The MFC starter program will include C++ source (.CPP) files, resource (.RC) files, header (.H) files, and a project (.DSP) file. The code generated in these starter files is based on MFC and provides the classes that wrap ISAPI to create and handle Internet Server Extensions and Filters.

There are three steps to this process. First, following the steps and choosing the options provided by the ISAPI Extension Wizard, you define the features of your program. Next, you compile and link the starter program. Finally, you add functionality to the starter files that the ISAPI Extension Wizard created.

What do you want to do?

  • Create an Internet server extension or filter

  • Learn more about Internet Server API extensions and filters


Create an ISAPI DLL with the ISAPI Extension Wizard

Home | Overview | Details | Sample

To create an ISAPI Extension or Filter .DLL using the ISAPI Extension Wizard

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the ISAPI Extension Wizard icon.

  3. Complete the steps of the ISAPI Extension Wizard by choosing the appropriate options for your program. Click here for a step-by-step explanation of the ISAPI Extension Wizard.

  4. Prepare your ISAPI .DLL for use. Click here for more information.

What do you want to know more about?

  • Build settings generated when you create a new program

  • Files created when you create a new program

  • Updating dependencies in a project


The ISAPI Extension Wizard: Step-by-Step

Home | Overview | Details | Sample

The ISAPI Extension Wizard series is a branching path of either 1 or 2 steps depending on whether you create a Filter or an Extension. You can move forward and backward through the steps and make changes to the options you have selected.

Help is available for every option in each step: right-click on the control for more information about each option.

To complete Step 1

  1. Choose whether you want to create a Filter or an Extension, or both, and then enter the appropriate Class Names and Descriptions.

  2. Choose whether you would like to use the MFC library as a shared DLL or a statically-linked library.

  3. If you are creating a filter, click Next and then click here for Step 2. If you are creating an Extension, click Finish.

To complete Step 2 when creating an ISAPI Filter

  1. Choose which notification priority you want for your Filter.

  2. Select the connection types you want your Filter to notice.

  3. Select the notification types you want your filter to process.

  4. Click Finish and then click here for more on how to prepare your ISAPI DLL for use.


Prepare the ISAPI DLL for Use

Home | Overview | Details | Sample

To prepare the ISAPI DLL for use

  1. Compile and link the ISAPI DLL starter files.

  2. Add functionality to ISAPI Extension Wizard starter files.

What do you want to know more about?

  • Compiling and linking

  • Build settings generated when you create a new program

  • Files created when you create a new program

  • Updating dependencies in a project


Add Functionality to an ISAPI DLL

Home | Overview | Details | Sample

After using the ISAPI Extension Wizard to create an ISAPI DLL, you get a working starter application with whatever functionality you asked for when completing the steps in the Wizard.

Your compiled program now implements the basic features of an MFC (.DLL) application. Your final step is to supply the application-specific source code and connect the components by defining what messages and commands the starter files should respond to.

What do you want to know more about?

  • How to write code in the wizard-generated classes to implement your ISAPI program. This is the functionality unique to your program

  • How to map client requests to member functions by writing a parse map

  • How to write a filter to manage incoming and/or outgoing data for the ISAPI server

  • Build settings generated when you create a new program

  • Files created when you create a new program

Updating dependencies in a project


Overview: Creating a Program That Supports a Database

Home | Overview | Details | Sample

When you create a new MFC program you can include database support as one of the options. You can provide your own database classes or use MFC database classes. MFC includes database classes for programming with Open Database Connectivity (ODBC) or with Data Access Objects (DAO).

To create a program that supports a database, you use the MFC AppWizard (EXE version) and in Step 2 you choose the appropriate database options. There are three options for database support:

  • Header files only This option provides the minimal level of database support in an MFC program. AppWizard includes the database header files and link libraries. You create any database-specific classes.

  • Database view without file support This option provides document support but no link support. AppWizard creates database header files, link libraries, and creates a record view and recordset for you.

  • Database view with file support This option provides document support and serialization support. AppWizard creates database header files, link libraries, and creates a record view and recordset for you.

Click here for more detailed information on choosing Database options when using the MFC AppWizard.

You can also create a direct database project, click here for more information.

What do you want to do?

  • Learn more about databases

  • Learn how to use the MFC AppWizard to create an MFC EXE program

  • See what MFC Class Library Tutorials are available to help me learn more about creating a database program?


Database Options in AppWizard

Home | Overview | Details | Sample

This topic describes the MFC database options available in Step 2 of the MFC AppWizard. These options include:

  • None

  • Only include header files

  • A database view, without file support

  • Both a database view and file support

A record view — derived from class CRecordView (for ODBC) or class CDaoRecordView (for DAO)— is a form view, based on a dialog template resource, that uses dialog data exchange (DDX) to exchange data between the view’s controls and a CRecordset-derived object (for ODBC) or a CDaoRecordset-derived object (for DAO). You can map the form’s controls to data members of a recordset. For more information about record views, see the article Record Views. For more information about recordsets, see the article Recordset (ODBC) or the article DAO Recordset.

No Database Support

AppWizard defaults to this option (“None” in the AppWizard dialog box) and adds no database support to your application.

Only Include Header Files

Choose this option for the minimum database support. AppWizard adds an #include directive for the header file that defines the database classes. The file AFXDB.H (for ODBC) and the file AFXDAO.H (for DAO) are included in STDAFX.H.

Note that if you do choose a database view with AppWizard, you will only be given the single #include that corresponds to your choice of ODBC or DAO. Your application probably won’t need access to both. When you don’t choose a database view, however, AppWizard can’t anticipate which you prefer, so it provides both.

With this support, you can use any of the database classes, related macros and global functions, and other items defined in the appropriate include file. AppWizard creates no database-related classes for you except for a view class and a recordset class if you choose one of the Database View options; you can create what you need later with ClassWizard.

AppWizard no longer explicitly adds libraries to the link line. The libraries are automatically included by special #pragma directives scattered throughout the MFC header files. You don’t need to worry about library names.

A Database View, Without File Support

Choose this option when you want an application with the following characteristics:

  • A view class derived from CRecordView or CDaoRecordView rather than CView.

    This view class makes your application form-based. AppWizard creates an empty dialog template resource to which you must later add dialog controls with the Visual C++ dialog editor.

  • A class derived from CRecordset or CDaoRecordset.

    The record view class contains a pointer to a recordset object based on this class. Record view controls are mapped to recordset field data members via dialog data exchange (DDX).

  • No disk-file user interface and serialization.

    A database application usually manages data record-by-record, interacting with the database, rather than managing whole data files.

  • No document-related File-menu commands.

    This option also creates a menu resource whose File menu lacks document-related commands: New, Open, Save, and Save As. Without serialization, you probably don’t need these commands.

Note Choosing this option makes the application single document interface (SDI). Choosing file support allows either SDI or MDI (multiple document interface).

This option creates a CDocument-derived class. In general, you’ll use this class to store a CRecordset object, or a pointer to one. For more information on how to use this document class, see the article MFC: Using Database Classes Without Documents and Views. The article discusses various document/view configurations, including applications with no document or view.

Both a Database View and File Support

Choose this option when you want an application with the following characteristics:

  • A view class derived from CRecordView or CDaoRecordView rather than CView.

    This view class makes your application form-based. AppWizard creates an empty dialog template resource to which you must later add dialog controls with the Visual C++ dialog editor.

  • A class derived from CRecordset or CDaoRecordset.

    The record view class contains a pointer to a recordset object based on this class. Record view controls are mapped to recordset field data members via dialog data exchange (DDX).

  • A disk-file interface in addition to a record view on the database.

    This application opens a disk file in addition to a database. The disk file might store, for example, “style sheet” information, so the user can configure, save, and quickly restore alternative views of the database.

Note For the last two options, AppWizard binds all columns of the table(s) you select to the recordset. If you don’t want all the columns, you can remove some of them later with ClassWizard. See the article ClassWizard: Binding Recordset Fields to Table Columns.

What do you want to know more about?

  • Databases

  • The MFC AppWizard

  • Using ClassWizard

  • Files created when you create a new program


Creating a Direct Database Project

Home | Overview | Details

You can use direct database debugging to test SQL stored procedures without creating an ODBC application to call the stored procedure. Direct database debugging bypasses the need for an ODBC application. For example, if you want to determine if a stored procedure works correctly, you can quickly create a direct database project and then directly test the SQL stored procedure.

Feature Only in Enterprise Edition Creating a direct database project is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

To create a Direct Database project

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the Database project icon.

What do you want to know more about?

Direct database debugging


Overview: Creating a Win32 Program

Home | Overview | How Do I | Details | Sample

A Win32 program is an executable application (.EXE) written in C or C++, using calls to the Win32 API rather than to MFC classes.

Visual C++ will create workspace and project files for your program, that you then add your own code to. There are two steps to this process. First, you use the Application icon to create project files for your program. Next, you prepare your program for use by modifying the source code that the wizard added (if any) or by adding source code files to the project.

What do you want to do?

  • Create a Win32 Program

  • Learn more about Win32 programming

  • Create a static library for my program

  • Create a Win32 DLL


Create a Win32 Program

Home | Overview | Details | Sample

To create a Win32 (exe) program

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the Application icon.

  3. In Step 1 of the wizard, specify the level of file support you want for the project.

  4. Click here for more information on how to prepare your non-MFC program for use.

What do you want to know more about?

  • The default build settings for a Win32 program

  • Files created when you create a new program

  • Updating dependencies in a project


Prepare the Win32 Program for Use

Home | Overview | How Do I | Details | Sample

To prepare the non-MFC program for use

  1. On the Project menu, point to Add to Project, then click Files to add your source code files to the project.

  2. Build the program.

What do you want to know more about?

  • How to build my program

  • How to work with files in the project workspace

  • The files types that are created for my program

  • The default build settings for a Win32 program

  • Updating dependencies in a project


Overview: Creating a Win32 DLL

Home | Overview | How Do I | Details | Sample

A Win32 DLL is a binary file (written in C or C++ and using calls to the Win32 API rather than to MFC classes), that acts as a shared library of functions that can be used simultaneously by multiple applications.

Visual C++ will create workspace and project files for your program that you then add your own code to. There are two steps to this process. First, you use the Dynamic Link-Library icon to create new project files for your Win32 DLL. Next, you prepare your program for use by adding code to the source files created by the wizard (if any) or by adding source code files to the project.

What do you want to do?

  • Create a Win32 DLL

  • Learn more about Win32 programming

  • Contents of the Platform SDK

  • Create an MFC DLL


Create a Win32 DLL

Home | Overview | Details | Sample

To create a Win32 DLL

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the Dynamic Link-Library icon.

  3. In Step 1 of the wizard, specify the level of file support for the project.

  4. Click here for more information on how to prepare your Win32 DLL for use.

What do you want to know more about?

  • The file types that are created for my program

  • The default build settings for a Win32 DLL

  • Updating dependencies in a project


Prepare the Win32 DLL for Use

Home | Overview | Details | Sample

To prepare the DLL for use

  1. On the Project menu, point to Add to Project, then click Files to add your source code files to the project.

  2. If needed, add a function called DllMain and add the initialization and termination code for the DLL to this function.

  3. Make sure you have exported the entry points to your DLL by using either the __declspec(dllexport) keyword or by listing the functions in the DLL’s .DEF file.

  4. Prepare a header file that includes the programs using your DLL. This header file should contain the declarations of the appropriate functions. When the header file is compiled for a DLL, use the __declspec(dllexport) keyword to export from the DLL. When the header file is compiled for a program that uses the DLL, use the declspec(dllimport) keyword.

  5. If your DLL uses __declspec(dllexport) or a .DEF file, an import library will be created automatically. In other situtations you will need to prepare an import library for your programs to link with by ensuring that the /IMPLIB linker switch is set when building your DLL.

  6. Build the DLL.

What do you want to know more about?

  • How a DLL exports functions

  • How to export functions from the DLL using .DEF files

  • How to export functions from the DLL using __declspec(dllexport)

  • How a program links to a DLL

  • How to initialize a DLL

  • The default build settings for a new Win32 DLL

  • How to test the Win32 DLL


Test the Win32 DLL

Home | Overview | Details | Sample

To test your DLL, you must have an application that uses the exported classes or calls the exported functions. Click here for suggestions on managing the project workspace for the calling application and the DLL.

To debug a DLL, you must specify the application that calls your DLL by clicking the Settings command on the Project menu. In the Project Settings dialog box, click the Debug tab. In the Executable for debug session box, specify which application to run while debugging.

What do you want to know more about?

  • How a DLL exports functions

  • How to export functions from the DLL using .DEF files

  • How to export functions from the DLL using __declspec(dllexport)

  • How a program links to a DLL

  • How to initialize a DLL

  • Debugging

  • The default build settings for a new Win32 DLL project


Overview: Creating a Static Library

Home | Overview | How Do I | Details | Sample

A static library is a file containing objects and their functions and data that is linked into your program when the executable file is built. This topic explains how to create the starter files and project settings for a static library. You can link a static library to an MFC-based program or to a non-MFC program for Windows written in C or C++, that makes calls to the Win32 API rather than to MFC classes.

There are two steps to this process. First, you use the Static Library icon to create files and project options. Next, you prepare your library for use by adding the appropriate classes and resources that you want to make available to calls from your program to it.

What do you want to do?

  • Create a Static Library

  • Learn about DLLs statically linked to MFC

  • Learn about the default build settings for a new static library project

  • Learn about the files created when you create a new program

  • See what MFC Class Library Tutorials are available to help me learn more about creating an MFC program


Create a Static Library

Home | Overview | Details | Sample

To create a non-MFC static library

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the Static Library icon.

  3. In Step 1 of the wizard, specify the level of file support you want for the project.

  4. Click here for more information on how to prepare your static library for use.

What do you want to know more about?

  • The default build settings for a new static library project

  • The file types that are created for my program

  • Updating dependencies in a project


Prepare the Static Library for Use

Home | Overview | How Do I | Details | Sample

To prepare the static library for use

  1. Add your source code files to the library.

  2. Prepare a header file for the programs using your static library to include.

  3. Build the static library.

  4. Test the code in your static library by linking it to a program that calls the functions in the library.

What do you want to know more about?

  • Compiling and Linking

  • The default build settings for a new static library project

  • The files types that are created for my program

Updating dependencies in a project


Overview: Creating a Utility Project

Home | Overview | How Do I | Details

When you create a utility project, no files are added to the project. The utility project does not generate any predetermined output files, such as a .LIB, .DLL or .EXE. A utility project can be used as a container for files you can build without a link step:

  • You can use a utility project as a master project for your subprojects.

  • A utility project can export a MAKEFILE.

  • A utility project has nothing but custom build rules; you must create custom build rules and add files.

  • Utility projects respect the list of specified outputs and checks to see if outputs are out of date.

What do you want to do?

  • Create a Utility Project


Create a Utility Project

Home | Overview | Details

To create a Utility Project

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the Dynamic Link-Library icon.


Overview: Creating a MAKEFILE Project

A MAKEFILE project is a command line project in which you tell a build engine the command line to execute. The default command is nmake but you can use any build tool.

The output file that you specify in a MAKEFILE project has no impact on the name that the build script generates; it only declares an intention.


Create a MAKEFILE Project

To create a non-MFC static library

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the MAKEFILE icon.

What do you want to know more about?

  • nmake


Overview: Creating a Console Program

Home | Overview | How Do I | Details | Sample

Console programs are developed with Console API functions, which provide character-mode support in console windows. The Visual C++ run-time libraries also provide output and input from console windows with standard I/O functions, such as printf() and scanf().

This topic explains how to create the starter files and project settings for a console program. Visual C++ will create a project file for your program that you then add your own elements to. There are two steps to this process. First, you use the Console icon to create a project file and project options for your program. Next, you prepare your project for use by adding the appropiate classes and resources or by adding code to the source files (if any) created by the wizard.

What do you want to do?

  • Create a console program


Create a Console Program

Home | Overview | How Do I | Details | Sample

To create a console program

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the Console Application icon.

  3. In Step 1 of the wizard, select the file support you want in the project.

  4. Prepare the console program for use

What do you want more information about?

  • The files types that are created for my program

  • The default build settings for a new console program

  • Updating dependencies in a project


Prepare the Console Program for Use

Home | Overview | How Do I | Details | Sample

To prepare the console program for use

  1. Add your source code files to the project.

  2. Build the console program.

What do you want to know more about?

  • How to build my program

  • How to work with files in the project workspace

  • The files types that are created for my program

  • The default build settings for a new console program

  • Updating dependencies in a project


Creating Custom AppWizards

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Using the standard MFC AppWizard as a reference, you can create Custom AppWizards that will create programs appropriate for your work environment. The topics listed below describe what custom AppWizards are, when they are useful, and how you create them.

What do you want to know more about?

  • Understanding custom AppWizards

  • An overview of creating a custom AppWizard

  • Customizing a generated AppWizard project

  • Debugging custom AppWizards

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


Understanding Custom AppWizards

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The MFC AppWizard is the tool to use when you need to create a new program. It quickly generates the starter files you need for the most common types of programs. But what about those special applications that are unique to your work? What do you do if you or your clients need to create programs with features that the standard MFC AppWizard can’t provide? The answer is that you can create custom AppWizards.

Custom AppWizards are useful for creating generic programs that can repetitively generate common functionality; programs that can be used over and over again.

Like the standard MFC AppWizard, a custom AppWizard presents the user with choices, tracks the user’s decisions, and uses those decisions to generate the code, resources, and project files that the build tools require to build a working starter application.

For example, if you work for a company where people are commonly developing ActiveX controls that use the same type of control container, you can create a custom AppWizard to generate generic control containers. You could even create the custom AppWizard so that the container is always also set up as an ActiveX document server.

Possibilities for custom AppWizards:

  • Create a custom AppWizard that is based on the code and resources in an existing project.

  • Modify code in the standard MFC AppWizard templates.

  • Add one or more steps to the standard MFC AppWizard’s steps.

  • Create a custom set of steps.

What do you want to know more about?

  • An overview of creating a custom AppWizard.

  • Using a custom AppWizard

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • Customizing a generated AppWizard project

  • Debugging custom AppWizards

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


Using a Custom AppWizard

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Once you have created a custom AppWizard, it is launched from the Projects tab on the New dialog box. When the custom AppWizard user finishes using the custom AppWizard, the New Project Information dialog box displays the name and features of the chosen project. The custom AppWizard functions just like the standard MFC AppWizard with regard to the New dialog box, and the New Project Information dialog boxes.

In fact, a custom AppWizard is just an extension of existing MFC AppWizard technology. A running custom AppWizard uses many of the services of the MFC AppWizard to do its work. Users of a custom AppWizard that is based on an existing application or based on the MFC AppWizard with no custom steps will not see any differences. A user of a more complex custom AppWizard will proceed through a sequence of steps much like they would if using the standard MFC AppWizard.

Both the standard MFC AppWizard and a custom AppWizard are implemented as two dialog boxes: an outer one and an inner one. The outer dialog box contains the title bar and the Help, Cancel, Back, Next, and Finish buttons. It serves as a master control panel and also frames the inner dialog box.

The inner dialog box can actually be one or more dialog boxes, each representing one step in the project generation process.

What do you want to know more about?

  • Understanding custom AppWizards

  • An overview of creating a custom AppWizard

  • Debugging custom AppWizards

  • Creating a ClassWizard information file template

  • Providing context-sensitive help


Overview of Creating a Custom AppWizard

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Creating a custom AppWizard requires the following steps:

  1. On the File menu, click New, click the Projects tab and then choose the Custom AppWizard icon.
    For more information, see How to Create a Custom AppWizard Project.

  2. Edit two text templates, CONFIRM.INF and NEWPROJ.INF. Your finished custom AppWizard uses these to create the custom AppWizard user’s program.
    For more information, see Understanding CONFIRM.INF and NEWPROJ.INF

  3. Create any other templates that your custom AppWizard requires.
    For more information, see Understanding Custom Resource Templates.

  4. Use the Visual C++ programming tools to add functionality to your custom AppWizard.

  5. Use the AppWizard API to add calls into MFCAPWZ.DLL to create communication between the finished custom AppWizard and the standard MFC AppWizard (MFCAPWZ.DLL).
    For more information, see AppWizard Programming Reference.

  6. After building a release version of your custom AppWizard, use the Visual C++ programming tools. A custom AppWizard is given an extension of .AWX, rather than .DLL, and is automatically added to the Microsoft Visual Studio\Common\msdev98\Template directory. Once in this directory, your custom AppWizard becomes a project type and shows up on the Projects tab in the New dialog box.

You’ll have to learn some of the inner workings of AppWizard to perform steps 3 and 5. But first, you need an overview of the players and the tools. The following table describes the players; the table after it describes the tools.

The Players

Players | Description
You | You are the custom AppWizard writer. Your job is to design and implement a custom AppWizard. In this documentation, “you” refers to a custom AppWizard writer.
Custom AppWizard user | You, or any other developer, who uses a custom AppWizard with the purpose of creating a program for one or more end users.
User | The end user who uses the program created from the project generated by the custom AppWizard. In this documentation, “user” refers to the end user.

As you can see, creating a custom AppWizard is a layered interaction between you (the custom AppWizard writer), the custom AppWizard user, and the end user who ultimately uses the program.

The following table describes the tools that you use (in addition to the compiler, linker, etc.) to create a custom AppWizard for a custom AppWizard user.

The Tools

Tools | Description
AppWizard | A tool that you use to create a program that is based on the Microsoft Foundation Class Library (MFC). AppWizard is composed of MFCAPWZ.DLL and all of the dynamic-link libraries (DLLs) containing localized resources (those with names described by APPWZ*.DLL).
Custom AppWizard | A tool that you use to create custom programs. Your custom AppWizard is used to create a program. The custom AppWizard appears, to its user, as one or more steps that are embedded within a framework that looks like AppWizard.
MFCAPWZ.DLL | The DLL that implements AppWizard. It also interacts with a finished custom AppWizard to lend it an AppWizard-like look and feel. MFCAPWZ.DLL has two different interfaces: an on-screen appearance that looks much like AppWizard (with a title bar and Help, Cancel, Back, Next, and Finish buttons), and an AppWizard API that you use to establish lines of communication and control between MFCAPWZ.DLL and your custom AppWizard.
CUSTMWZ.AWX | The dynamic-link library, which is itself a custom AppWizard, that implements the Custom AppWizard project type. You select this project type from Projects tab of the New dialog box in order to choose the features of your custom AppWizard. The CUSTMWZ.AWX source code is included as a sample program.
AppWizard API | The application programming interface that provides you with calls into MFCAPWZ.DLL. You use the API to specify custom AppWizard and MFCAPWZ.DLL behavior in reaction to a custom AppWizard user’s on-screen manipulation of the Help, Cancel, Back, Next, and Finish buttons. For more information on the AppWizard API, see AppWizard Programming Reference.
Custom resource templates | There are two types of custom resource templates: binary and text. A finished custom AppWizard uses these templates to create a final application. For more information, see Standard Custom Resource Templates.
Binary templates | Binary templates are not parsed by MFCAPWZ.DLL during the application generation process. They are copied verbatim to a new application. Binary templates can include, but are not restricted to, files such as .BMP and .RTF. For more information, see Understanding Binary Templates.
Text templates | Text templates are parsed by MFCAPWZ.DLL during the application generation process. They can, for example, contain source code, macros, and directives that a custom AppWizard can use to generate a new project’s source-code files. Typically, the new project’s final application is built from these source files. Text templates can include, but are not restricted to, files such as .H, .CPP, .RC, .CLW, .ODL, .RTF, and .RC2. For more information, see Understanding Text Templates.

What do you want to know more about?

  • How to create a custom AppWizard project

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • Customizing a generated AppWizard project

  • Custom resource templates

  • Text templates

  • How macros get their values

  • How to specify macros in directives or text

  • Binary templates

  • Debugging custom AppWizards

  • Creating a ClassWizard information file Template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


How to Create a Custom AppWizard Project

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

You use the standard MFC AppWizard and the build tools to create a custom AppWizard. You can create custom AppWizards based on one of the three categories: an existing project, the standard MFC AppWizard steps, or your own custom steps. These are described below.

An Existing Project

By choosing this category, you can leverage code from a workspace that contains a single existing project. The project’s files must have originally been created by the standard MFC AppWizard, and the names of the existing project’s files and classes (CYourAppView, CYourAppDoc, etc.) should be those generated by the MFC AppWizard.

The existing project’s name must not contain nonalphanumeric characters, such as DBCS characters. The existing files, originally created from the standard MFC AppWizard, can include minor changes or additions, but major changes can introduce flaws into your new custom AppWizard.

If the base class’s default, MFC AppWizard-provided class, and/or filenames have been modified, Custom AppWizard cannot convert them to macro form as it adds them to the text templates that it generates. This is also true if you use ClassWizard to add classes to a default MFC AppWizard project. Custom AppWizard will still parse the modified names and add them to the templates, and your custom AppWizard will generate an application, but your custom AppWizard will not be able to modify the names based on the project name provided by your custom AppWizard’s user. You can work around this by adding the appropriate macros to the names in the text templates. For more information on text templates, see Understanding Text Templates. For more information on macros, see How Macros Get Their Values.

You may find it useful to examine the Custmwz.awx source code, found in the Microsoft Visual Studio\Common\msdev98\bin\ide directory that is included as a sample program.

Standard AppWizard Steps

By choosing this category, you can use one of the existing sequences of the standard MFC AppWizard steps that create an executable file or a DLL. You can use the MFC AppWizard steps by themselves, or add your own custom steps to them.

Note You can’t connect your own custom AppWizard code with existing MFC AppWizard dialog templates. For example, if your custom AppWizard uses the standard ActiveX options page, AppWizard will use its own ActiveX options step dialog template and dialog class; you cannot modify the AppWizard dialog template or class.

Your Own Custom Steps

By choosing this category, you can create a custom AppWizard that presents a completely new set of custom steps to the user.

Creating a Custom AppWizard

The procedures below list the steps necessary to create a custom AppWizard based on any of the three categories: an existing project, the standard AppWizard steps, or your own custom steps. The first procedure describes how to use the Custom AppWizard project type to create a custom AppWizard.

To create a custom AppWizard

  1. On the File menu, click New and then click the Projects tab.

  2. Specify the Project Name, Location, Workspace, Dependency, and Platforms options and then double-click the Custom AppWizard icon.

    The name that you specify in the Name text box is used to derive the default names for the CCustomAppWiz class and its files.

To specify a custom AppWizard type, name, and number of steps

  1. From Custom AppWizard Step 1 of 2, select a custom AppWizard category:
    • An existing project

      Select this option if you want your custom AppWizard to generate code, resource, and project files that are based on those found in a workspace that contains a single existing project. For more information on this option, see How to Create a Custom AppWizard Project.

      If you select this option, the AppWizard title bar displays “Step 1 of 2.” The text box for specifying the number of custom steps is grayed out because the features of the resulting custom AppWizard project are defined by the features of the existing project; you will not need to provide any custom AppWizard steps.

    • Standard AppWizard steps

      Select this option if you want your custom AppWizard to use an existing sequence of AppWizard steps. For more information on this option, see How to Create a Custom AppWizard Project.

    • Your own custom steps

      Choose this option if you want to create an entirely new custom AppWizard.

  2. Type a name for your custom AppWizard.

  3. If you have chosen to base your custom AppWizard on either the standard MFC AppWizard steps or a completely custom set of steps, specify the required number of custom steps.

    Note If your project is based on the standard MFC AppWizard steps, type a number only if you plan to create steps other than the standard ones.

    For each step that you specify, MFCAPWZ.DLL will provide a resource template that you can edit in the dialog editor, and a CAppWizStepDlg class derived from the MFC library’s CDialog class.

To specify the location of an existing project

If you’ve chosen to base your custom AppWizard on an existing project, you must specify the location of the existing project:

  1. From Custom AppWizard Step 1 of 2, click Next.

  2. In Step 2 of 2, type or use Browse to find the path that contains the existing project on which your custom AppWizard will be based.

To choose the type of standard MFC AppWizard steps

  1. From Custom AppWizard Step 2 of 2, select either AppWizard Executable or AppWizard Dynamic Link Library.

  2. Select the languages that your custom AppWizard will support.

    The list box contains a language name for each language DLL in your Microsoft Visual Studio\Common\msdev98\bin\ide directory. The names of these DLLs take the form APPWZ*.DLL. For example, if Microsoft Visual Studio\Common\msdev98\bin\ide contains APPWZENU.DLL and APPWZDEU.DLL, the list box will list both English and German.

    For each language you select from the list box, AppWizard will copy language-specific versions of the standard MFC AppWizard resource templates from the associated language DLL to your custom AppWizard project’s template directory. Then, after your finished custom AppWizard is copied to a custom AppWizard user’s Microsoft Visual Studio\Common\msdev98\Template directory, the custom AppWizard user can use your custom AppWizard to generate projects that support any of the languages you select.

    Note The language DLLs (such as APPWZENU.DLL and APPWZDEU.DLL) contain only standard AppWizard resource templates. You must supply any nonstandard resource templates required by applications that your custom AppWizard creates. For a complete list of the standard AppWizard resource templates, see Standard Custom Resource Templates.

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • Customizing a generated AppWizard project

  • Custom resource templates

  • Debugging custom AppWizards

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • AppWizard Language Support for Far East Languages

  • The AppWizard Programming Reference


Understanding the Files that AppWizard Creates

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Your custom AppWizard uses the name that you specify in the Project Name box on the Projects tab of the New dialog box to derive names for some of its files and classes.

You’ll undoubtedly want to examine the source-code files you create. If you chose to have AppWizard add comments to the files it creates for your project, AppWizard will also create a text file, README.TXT, in your new application directory. This file explains the contents and uses of the other new files created by AppWizard.

What do you want to know more about?

  • Understanding custom AppWizards

  • Using a custom AppWizard

  • An overview of creating a custom AppWizard

  • Adding functionality to a custom AppWizard

  • Customizing a generated AppWizard project


Adding Functionality to Your Custom AppWizard

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

You add functionality to a custom AppWizard in the same manner that you add functionality to any other MFC AppWizard project. That is, you use the resource editors to edit your project’s resources and use the WizardBar, ClassWizard, and the text editor to edit your code.

The only difference between adding functionality to a standard MFC AppWizard project and to a custom AppWizard project is dealing with custom resource templates. After examining your project’s structure, you’ll note that it contains a TEMPLATE directory. The files in this directory contain custom resource templates. MFCAPWZ.DLL and your finished custom AppWizard will use these to create the custom AppWizard user’s application.

Adding Functionality to Your Custom AppWizard

What do you want to know more about?

  • The files that AppWizard creates

  • Customizing a generated AppWizard project

  • Custom resource templates

  • CONFIRM.INF and NEWPROJ.INF

  • Text templates

  • How macros get their values

  • How to specify macros in directives or text

  • Binary templates

  • Debugging custom AppWizards

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


Customizing the Generated Custom AppWizard Project

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

You can customize AppWizard to change the project settings after it has created the new project. For example, you could have your custom AppWizard add special preprocessor macro defines to the compiler settings; have it add or remove import libraries from the linker's options, or add a custom build rule that is run after the project is built which registers its server objects or copies it to a special location for testing.

Your custom AppWizard can perform any or all of these tasks after your project is generated. Simply override CCustomAppWiz::CustomizeProject with the code that customizes the project the way you want it to be.

Your code accesses the project through the IBuildProject interface. This is a dual interface on the BuildProject object. Note that this is the same object that is accessed by VBScript macros.

What do you want to know more about?

  • The files that AppWizard creates

  • How macros get their values

  • How to specify macros in directives or text

  • Debugging custom AppWizards

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


Understanding Custom Resource Templates

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The MFC AppWizard obtains the building blocks for the code, resource, and project files it creates from special files called custom resource templates. There are two types of custom resource templates: text templates and binary templates. Text templates are used to create the source files for a project, and binary templates usually contain bitmaps for user-interface components, such as toolbars.

AppWizard always provides you with a copy of the CONFIRM.INF and NEWPROJ.INF templates and, if you use existing sequences of standard MFC AppWizard steps, AppWizard copies its own custom resource templates into your custom AppWizard project for you to use and/or modify. You can also create your own templates and add them to your custom AppWizard project.

Custom resource templates are resources of type “TEMPLATE”. You can see these if you double-click your project’s resource script file (.RC) in the Workspace window. All custom resource templates are in the folder called “TEMPLATE”. Because these are custom resources, they are treated as binary data. If you double-click a custom resource type in the Project Workspace window, the associated file opens in a binary editor. If you want to edit a custom resource, you must know the actual type it represents and choose that type from the Open As list in the Open dialog box.

To open a custom resource type in the appropriate editor

  1. On the File menu, click Open.

  2. Select the drive and directories where the template is stored.

  3. In the Files of type box, set the types of files to display.

    Files with the chosen extension are displayed in the File Name box.

    This box serves as a filter to display all files with a given extension. For example, selecting Image Files in the Files of Type box displays all files with *.BMP, *.DIB, *.ICO, and *.CUR extensions in the File name box.

  4. In the File Name box, select a filename.

  5. From the Open As list, select the type of file that describes the template you wish to open.

    The Auto type will correctly recognize custom resource template file extensions such as .BMP, .H, and .CPP and open an associated file in the correct editor. Select Text from the Open As list to edit custom resource templates that represent resource scripts (.RC files).

To create a custom resource template

  1. Copy the file you wish to import as a custom resource template to your project’s Template directory.

  2. On the Insert menu, click Resource.

  3. From the Resource type list, select the type of the custom resource template and click Import.

  4. In the Look in box, select your project’s Template directory.

  5. In the Files of type box, set the types of files to display.

    This box serves as a filter to display all files with a given extension. For example, selecting Icons in the Files of type box displays all files with *.ICO extension in the File Name box.

  6. In the File name box, select a file name.

  7. From the Open As list, select Custom and then click Import.

  8. From the Resource Type list, choose “Template”.

    The file is imported into your project as a custom resource type and opened in the binary data editor.

    The custom resource type is added to your project under your projects “Template” folder, which is available by selecting the ResourceView tab in the Project Workspace window. The custom resource template type is given an ID of IDR_TEMPLATE*, where * is a number that is unique within the “Template” folder. You can use the Properties command on the pop-up menu to change the ID. To activate the ID’s pop-up menu, place the mouse cursor on the new custom resource template’s ID in the “Template” window and click the right mouse button.

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • Text templates

  • How macros get their values

  • How to specify macros in directives or text

  • Binary templates

  • Creating a ClassWizard information file template

  • The AppWizard Programming Reference


Understanding Text Templates

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

A text template is a type of custom resource template. AppWizard uses the content of text templates to create the source files of a new project. Text templates typically contain lines of source code, such as C++ code or resource-script directives. Text templates also contain macros and directives that AppWizard uses to determine the final content of template-generated source files.

AppWizard puts templates into the TEMPLATE directory of a generated project. Once templates are part of a project, you can either use them without modification or edit them to add custom functionality to your custom AppWizard. You can also add your own text templates to a project.

The following code-template fragment shows C++ code with embedded macros and directives. The values of macros such as $$ROOT$$ and $$APP_CLASS$$ control the names of files and classes. The existence of macros such as VERBOSE controls whether flow-of-control directives, such as $$IF, evaluate to true.

For more information on macros, see How Macros Get Their Values. For more information on directives, see Standard AppWizard Directives.

// $$root$$.h : main header file for the $$ROOT$$ application

#include "resource.h"      // main symbols

////////////////////////////////////////////////////////////////////////
// $$APP_CLASS$$:
// See $$root$$.cpp for the implementation of this class

class $$APP_CLASS$$ : public $$APP_BASE_CLASS$$
{
public:
   $$APP_CLASS$$();

// Overrides
   // ClassWizard generated virtual function
   // overrides
   //{{AFX_VIRTUAL($$APP_CLASS$$)
   public:
   virtual BOOL InitInstance();
   //}}AFX_VIRTUAL

// Implementation

   //{{AFX_MSG($$APP_CLASS$$)
$$IF(VERBOSE)
   // NOTE - the ClassWizard will add and
   //      remove member functions here.
   //    DO NOT EDIT what you see in these
   //      blocks of generated code!
$$ENDIF
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • Custom resource templates

  • CONFIRM.INF and NEWPROJ.INF

  • How macros get their values

  • How to specify macros in directives or text

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


Understanding CONFIRM.INF and NEWPROJ.INF

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

CONFIRM.INF and NEWPROJ.INF are special text templates that MFCAPWZ.DLL (AppWizard) inserts into every custom AppWizard project. They are the blueprints that a custom AppWizard uses to construct the project files from which a final, end-user application can be built. The content of CONFIRM.INF becomes the content of the New Project Information dialog box. This presentation of information in the New Project Information dialog box allows a user to examine their chosen project features. NEWPROJ.INF contains the instructions that AppWizard uses to construct a user’s project.

AppWizard will provide CONFIRM.INF and NEWPROJ.INF templates in varying states of readiness, depending on whether you choose to base your custom AppWizard project on:

  • An existing project

    In this case, the content of NEWPROJ.INF is based on the content of the existing project. CONFIRM.INF is left empty; you will need to add text, macros, and directives to CONFIRM.INF that describe each feature a user can choose.

  • Standard MFC AppWizard steps

    In this case, the content of both templates is based on the existing MFC AppWizard steps. If you add your own custom steps to the standard MFC AppWizard steps, you’ll need to add text, macros, and directives to CONFIRM.INF that reflect each feature a custom AppWizard user can choose in each custom step. You will also need to add statements, macros, and directives to NEWPROJ.INF that can build a project for any combination of features a custom AppWizard user can select from the custom steps.

  • Your own custom steps

    In this case, both templates are empty. You must add text, macros, and directives to CONFIRM.INF that reflect each feature a user can choose in each custom step. You will also need to add statements, macros, and directives to NEWPROJ.INF so that it can build a project for any combination of features a user can select from the custom steps.

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • CONFIRM.INF

  • NEWPROJ.INF

  • Text templates

  • How macros get their values

  • How to specify macros in directives or text

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


CONFIRM.INF

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

CONFIRM.INF contains a human-readable description of each project component (such as the project name and the names of its primary classes). It also contains a description of each feature that a custom AppWizard user can select from each step. The following code shows how macros and flow-of-control directives are used to generalize the content of a CONFIRM.INF:

$$// confirm.inf = the text sent to the New Project
$$// Information dialog box
Application type of $$ROOT$$:
    Dialog-Based Application targeting:
        Win32

Classes to be created:
    Application: $$APP_CLASS$$ in $$ROOT$$.h and $$ROOT$$.cpp
    Dialog: $$DLG_CLASS$$ in $$DLG_HFILE$$.h and $$DLG_IFILE$$.cpp

Features:
   + About box on system menu
$$IF(INDENTED_BRACES)
   + Curly braces indented from previous level
$$ELSE // !INDENTED_BRACES
   + Curly braces flush with previous level
$$ENDIF // NOT_INDENTED_BRACES
$$IF(COMPANY_LOGO)
   + A company logo
$$ENDIF //COMPANY_LOGO
$$IF(3-D)
   + 3D Controls
$$ENDIF //3-D

This example of CONFIRM.INF contains lines of text (such as Classes to be created:), macros (such as $$APP_CLASS$$ and $$ROOT$$), and flow-of-control directives (such as $$IF and $$ENDIF). Once a user clicks Finish in a custom AppWizard, MFCAPWZ.DLL parses CONFIRM.INF as follows:

  • Each line of text is gathered into a CString object, and each encountered macro is expanded.

  • Any line beginning with $$// is a comment and is ignored.

  • Any line of text between an $$IF and an $$ENDIF is converted to a CString if the associated macro, such as INDENTED_BRACES and COMPANY_LOGO, exists and thus evaluates to true.

  • The resulting CStrings reflect the custom AppWizard user’s choices and are written to the New Project Information dialog box. Thus, they can view the features of their proposed project.

What do you want to know more about?

  • Text template parsing

  • An overview of creating a custom AppWizard

  • How to create a custom AppWizard project

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • CONFIRM.INF and NEWPROJ.INF

  • NEWPROJ.INF

  • Text templates

  • How macros get their values

  • How to specify macros in directives or text

  • Creating a ClassWizard information file template

  • Providing context-sensitive help

  • The AppWizard Programming Reference


NEWPROJ.INF

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

NEWPROJ.INF contains the instructions that MFCAPWZ.DLL uses to construct a custom AppWizard user’s project. The instructions are statements, directives, and macros that work together to describe the structure of a project. The following code shows how statements and macros are used to generalize the instructions of a NEWPROJ.INF file:

dlgroot.rc   .\$$ROOT$$.rc
dlgroot.clw   .\$$ROOT$$.clw
dlgroot.h   .\$$ROOT$$.h
dlgroot.cpp   .\$$ROOT$$.cpp
dialog.h   .\$$ROOT$$dlg.h
dialog.cpp   .\$$ROOT$$dlg.cpp
readme.txt   .\readme.txt
resource.h   .\resource.h
stdafx.h   .\stdafx.h
stdafx.cpp   .\stdafx.cpp
/RES
:=root.ico   .\res\$$ROOT$$.ico
:root.rc2   .\res\$$ROOT$$.rc2

In general, there are two kinds of NEWPROJ.INF statements: those that create directories, and those that fill the directories with files. In the previous example, the /RES statement causes MFCAPWZ.DLL to create a project subdirectory named RES. The dlgroot.rc  .\$$ROOT$$.rc statement causes MFCAPWZ.DLL to look for a custom resource template named DLGROOT.RC, give it a name determined by the value of the $$ROOT$$ macro, and place the resulting file in the new project’s root directory. The file is added to the project, so that it will be part of the build process when the user builds the project. For more information on the NEWPROJ.INF statements, see NEWPROJ.INF Statements.

For brevity, directives (such as $$IF, $$ELSE, and $$ENDIF) are not shown in the previous example, but they can be used as shown in the CONFIRM.INF example. For more information on directives, see Standard AppWizard Directives. For more information on macros, see How Macros Get Their Values.

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • How to create a custom AppWizard project

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • CONFIRM.INF and NEWPROJ.INF

  • Text templates

  • Text template parsing

  • How macros get their values

  • How to specify macros in directives or text

  • Creating a ClassWizard information file template

  • The AppWizard Programming Reference


Understanding Text Template Parsing

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The function CCustomAppWiz::ProcessTemplate parses a template line by line and passes everything that is not a macro or directive directly to an output stream. If a line contains a macro, which is not an argument to a directive, ProcessTemplate replaces the macro with its associated value, retrieved from the dictionary, and passes the altered line to the output stream. For example, given a project named MyProject and an output stream named ROOT.CPP, the following line in a text template:

#include "$$root$$.h"

becomes

#include "MyProject.h"

in a project file named MYPROJECT.CPP. For more information on macros, see How Macros Get Their Values.

If a line is a directive, ProcessTemplate obeys the rules set down by the directive. For more information on directives, see Standard MFC AppWizard Directives.

ProcessTemplate passes the parsed string to MFCAPWZ.DLL. If the output stream is directed to CONFIRM.INF or NEWPROJ.INF, MFCAPWZ.DLL will use the files during the project generation process. For more information on these files, see CONFIRM.INF and NEWPROJ.INF.

If the output stream represents a source file, MFCAPWZ.DLL does no further processing of the file. Instead, MFCAPWZ.DLL inserts the file into a new project structure following rules set out in NEWPROJ.INF.

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • Custom resource templates

  • CONFIRM.INF and NEWPROJ.INF

  • Text templates

  • How Macros Get Their Values

  • How to specify macros in directives or text

  • Creating a ClassWizard information file template

  • The AppWizard Programming Reference


How Macros Get Their Values

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

There are two kinds of macros: standard MFC AppWizard macros and those you create. Macros are created by adding them to a CMapStringToString dictionary named project aw.m_Dictionary that is declared in projectAW.H.

The MFC AppWizard gathers the values for some of its standard macros from the Projects tab of the New dialog box. It then uses these values to name a user’s project, files, and classes. AppWizard also uses macros that represent project features, such as 3D, TOOLBAR, and STATUSBAR. For more information on the standard MFC AppWizard macros, see Standard AppWizard Macros and CCustomAppWiz::m_Dictionary.

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • Adding functionality to a custom AppWizard

  • Custom resource templates

  • CONFIRM.INF and NEWPROJ.INF

  • Text templates

  • Text template parsing

  • How to specify macros in directives or text

  • The AppWizard Programming Reference

  • CCustomAppWiz::m_Dictionary


How to Specify Macros in Directives or Text

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

A macro name that is used as an argument to a directive, such as $$IF, does not need dollar signs ($$) to mark its beginning and end; any dollar signs found are interpreted as part of the macro’s name. For instance, the CCustomAppWiz::ProcessTemplate function’s parser treats both AMACRO and $$AMACRO$$ as macro names in the following two directive statements:

$$IF(AMACRO);
$$IF($$AMACRO$$);

A macro name in text, however, requires dollar signs ($$) to mark its beginning and end, as shown in the following fragment extracted from one of AppWizard’s custom resource templates:

///////////////////////////////////////////////////////
// $$APP_CLASS$$

BEGIN_MESSAGE_MAP($$APP_CLASS$$, $$APP_BASE_CLASS$$)
   //{{AFX_MSG_MAP($$APP_CLASS$$)
$$IF(VERBOSE)
      // NOTE - the ClassWizard will add and
      //      remove mapping macros here.
      //    DO NOT EDIT what you see in these
      //      blocks of generated code!
$$ENDIF
   //}}AFX_MSG
   ON_COMMAND(ID_HELP, CWinApp::OnHelp)
END_MESSAGE_MAP()

For more information on macros, see How Macros Get Their Values.

What do you want to know more about?

  • Adding functionality to a custom AppWizard

  • Custom resource templates

  • CONFIRM.INF and NEWPROJ.INF

  • Text templates

  • Text template parsing

  • How macros get their values

  • Binary templates

  • The AppWizard Programming Reference


Understanding Binary Templates

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

A binary template is a type of custom resource template. Binary templates usually contain bitmaps. These bitmaps are the user-interface components, such as toolbar buttons and icons, that the MFC AppWizard and a custom AppWizard use when generating a project. Binary templates do not contain macros or directives and are not parsed. They are, instead, copied verbatim into the end user’s project.

What do you want to know more about?

  • Adding functionality to a custom AppWizard

  • Custom resource templates

  • The AppWizard Programming Reference


Debugging Custom AppWizards

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

When MFCAPWZ.DLL generates your starter custom AppWizard project, it provides you with both Release and Pseudo Debug projects. The Pseudo Debug project is a Release project that disables optimizations and generates debugging information using the compiler’s Program Database (/Zi) option and the linker’s Generate Debug Information (/DEBUG) option. These option settings allow you to use the debugger while you are developing your custom AppWizard.

You must use the Pseudo Debug project to debug your custom AppWizard. Release projects (including Pseudo Debug projects) and Debug projects use two different and incompatible memory allocators. You do not have access to the Debug versions of the Visual C++ binarys. Using the Pseudo Debug project allows your custom AppWizard and the Release version of the Visual C++ binarys to use the same memory allocator.

A Pseudo Debug project defines the _PSEUDO_DEBUG preprocessor symbol, rather than the _DEBUG preprocessor symbol that signals a normal debug project, and uses its own local copies of the ASSERT, TRACE, and VERIFY debugging macros. You can find these macros in the generated files DEBUG.H and DEBUG.CPP.

The ASSERT, ASSERT_VALID, TRACE, and VERIFY macros that exist in the MFC code are not available to you because your custom AppWizard must use the Release version of MFC. This means that these macros are not available if you inadvertently write code that would trigger them.

To debug your custom AppWizard

  1. With your custom AppWizard’s project open, click the Settings command on the Project menu.

  2. Click the Debug tab.

  3. In the Executable for debug session box, type the location of MSDEV.EXE. For example, C:\Microsoft Visual Studio\Common\msdev98\bin\MSDEV.EXE.

    The next time you start the debugger, a new instance of the integrated development environment will launch.

  4. Use the original instance of integrated development environment to set breakpoints in your custom AppWizard code and to examine its data using the Watch window and other debugging tools as needed.

  5. Use the second instance of integrated development environment to launch your custom AppWizard for debugging.

What do you want to know more about?

  • An overview of creating a custom AppWizard

  • Adding functionality to a custom AppWizard

  • Creating a ClassWizard information file template

  • The AppWizard Programming Reference


Creating a ClassWizard Information File Template

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Custom AppWizard project adds a custom resource template for generating a ClassWizard Information (.CLW) file to the following types of new custom AppWizard projects:

  • Those based on an existing project, if the existing project contained a .CLW file (which it should).

  • Those based on an existing sequence of standard AppWizard steps.

If your custom AppWizard generates a .CLW file and you alter your custom AppWizard so that it generates projects that contain more classes than CUSTMWZ.AWX originally generated, then those additional classes will not automatically appear in the .CLW file your custom AppWizard generates. The custom AppWizard user will notice upon opening ClassWizard for the project your custom AppWizard generated that the additional classes are not available.

To avoid this problem, edit your custom AppWizard’s NEWPROJ.INF file so that it no longer generates a default .CLW. Then, when the custom AppWizard user attempts to use ClassWizard, ClassWizard presents a dialog box that notes that no .CLW file exists and offers to build one. The .CLW file is built after the user clicks Yes.

What do you want to know more about?

  • MFC classes supported by ClassWizard

  • Rebuilding the ClassWizard (.CLW) file

  • Custom resource templates


Providing Context-Sensitive Help

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Custom AppWizard project type provides you with the tools you need to create a help file that describes your custom steps:

  • A starter rich-text (.RTF) file, HLP\project.RTF, containing a topic for each custom step that the Custom AppWizard project type generated for you. You can use any rich-text format word processor, such as Microsoft Word, to add information to each custom-step topic in your project.RTF file.

  • A help project (.HPJ) file to control compiling your project.RTF file into a WinHelp help file.

  • Custom build rules on the .hpj, .cnt and resource.h file control the creation of the .HLP file from within the development environment.

Note You cannot integrate your custom AppWizard’s help with the help system in your integrated development environment. But if you build a custom AppWizard that uses an existing sequence of AppWizard steps, your custom AppWizard will automatically use the help file that was created for the standard AppWizard steps. Your custom AppWizard will use your own WinHelp help file for the custom steps. The effect is not seen by the end user.

Your custom AppWizard, which has the extension: .AWX, and its help file must use the same base filename, and both must reside in Microsoft Visual Studio\Common\msdev98\Template directory. When the end user clicks a custom step’s Help button, MFCAPWZ.DLL invokes WinHelp and passes it the current step’s help ID and the name of your custom AppWizard’s help file.

What do you want to know more about?

  • Help: Authoring Help Topics

  • Custom AppWizards

  • Using a custom AppWizard

  • An overview of creating a custom AppWizard

  • The files that AppWizard creates

  • Adding functionality to a custom AppWizard

  • Custom resource templates

  • The AppWizard Programming Reference


Creating an Extended Stored Procedure

Feature Only in Enterprise Editions Using the Extended Stored Procedure Wizard to create an extended stored procedure is supported only in Visual C++ Enterprise Editions. For more information, see Visual C++ Editions.

You can easily create SQL Server extended stored procedures (XPROC) with the Extended Stored Procedure Wizard in Visual C++. An extended stored procedure is an extern C function, exported from a Win32 DLL, that you can call from within SQL Server. An extended stored procedure is called like a stored procedure but is run on the server like any compiled process. Unlike an SQL Server stored procedure, which requires you to use SQL statements, an extended stored procedure lets you use Win32 APIs and Open Data Services (ODS) Open Data Services calls.

For more information, search the Knowledge Base for an article on extended stored procedures.

What do you want to know more about?

Using the Wizard to Create an Extended Stored Procedure

Registering the Extended Stored Procedure

Calling the Extended Stored Procedure

Adding Functionality to the Extended Stored Procedure

Debugging an Extended Stored Procedure


Using the Wizard to Create an Extended Stored Procedure

Feature Only in Enterprise Editions Using the Extended Stored Procedure Wizard to create an extended stored procedure is supported only in Visual C++ Enterprise Editions. For more information, see Visual C++ Editions.

You can use the Extended Stored Procedure wizard to generate a Win32 DLL project, with the proper initialization code, that contains one exported function. The wizard will also include the header file (srv.h) and library (opends60.lib) needed for using ODS. The one function that is created includes code for a sample program, utilizing ODS.

To create an extended stored procedure

  1. Choose New from the File menu.

  2. Click the Projects tab.

  3. Select Extended Stored Procedure AppWizard from the list of project types.

  4. Assign a name to the project and click OK.

  5. In Step 1, the wizard will prompt you for a name for your procedure. This name will be assigned to an exported Win32 function. Extended stored procedure names commonly begin with xp_.

    After assigning a name to your extended stored procedure click OK. The wizard will generate project files:

    proc.cpp The exported Win32 function, which is the extended stored procedure.

    projname.dsp The Visual C++ project file.

    projname.cpp A file that includes DLL initialization code.

    StdAfx.h An include file for standard system include files, or project-specific include files that are used frequently.

    StdAfx.cpp A source file that includes just the standard includes.

Compiling the generated project will generate a DLL, projname.DLL.


Registering the Extended Stored Procedure

Feature Only in Enterprise Editions Using the Extended Stored Procedure Wizard to create an extended stored procedure is supported only in Visual C++ Enterprise Editions. For more information, see Visual C++ Editions.

You must register an extended stored procedure with SQL Server before it can be used. You can register the extended stored procedure using a Visual Studio Database Project.

To register an extended stored procedure

  1. Create a database project (see Visual C++ information in Creating a Database Project), adding it to your current workspace, and add a data connection for the server where you want to register the extended stored procedure. You must use the server's Master database.

  2. Click the Data View tab and open the folder for your data connection. You will see a sub-folder for the extended stored procedures on that server.

  3. Right-click on the Extended Stored Procedures folder and choose New Extended Stored Procedure from the shortcut menu. A dialog box will prompt you for the name of your extended stored procedure and the name of the DLL. It is best not to include a full path to the DLL, just the filename, for example MyXp.DLL not c:\MyVCProjects\MyXp\debug\MyXp.DLL.

  4. Copy the DLL to the directory that contains sqlservr.exe, for example c:\mssql\binn on the server machine, or a directory that is included in the system search path for that server. SQL Server uses the Win32 API LoadLibrary to locate extended stored procedure DLLs so your new DLL needs to reside in the system path. In the Project Settings dialog box you can use a Post-Build step (see Specifying Build Rules that Run After the Build Process) to automate copying the DLL to the correct directory.


Calling the Extended Stored Procedure

Feature Only in Enterprise Editions Using the Extended Stored Procedure Wizard to create an extended stored procedure is supported only in Visual C++ Enterprise Editions. For more information, see Visual C++ Editions.

One way you can call the new extended stored procedure is from an SQL script file.

To call an extended stored procedure

  1. Make sure the active project is set to the database project created in the previous step.

  2. Choose New from the File menu.

  3. Click the Files tab, then choose SQL Script File from the list of file types. You will now have a blank script file in the Visual C++ editor. If the extended stored procedure's name is xp_MyXp, the following code would cause the extended stored procedure to be executed:
    EXEC xp_MyXp
  4. To run the script, right-click on the editor window and choose Run from the shortcut menu.

If the extended stored procedure produces any output, you can view the output in the Results pane.

Note SQL Server does not perform parameter checking on extended stored procedures. It is up to the caller of the extended stored procedure to know the required parameters and then pass them accordingly.


Adding Functionality to the Stored Procedure

Adding Functionality to the Extended Stored Procedure

Feature Only in Enterprise Editions Using the Extended Stored Procedure Wizard to create an extended stored procedure is supported only in Visual C++ Enterprise Editions. For more information, see Visual C++ Editions.

Files generated by the Extended Stored Procedure AppWizard are a starting point for creating an extended stored procedure. You will add your own code to enhance the generated extended stored procedure function. You can also add more exported functions to the project and have several extended stored procedures contained within a single DLL.

Typically, you will use ODS and Win32 API calls to enhance your extended stored procedure.


Creating a Microsoft Cluster Resource Type

Overview: Creating a Microsoft Cluster Resource Type

The Cluster Resource Type Wizard creates two projects that you can deploy on a Microsoft Cluster Server to manage and monitor resources (applications) on the cluster:

  • Resource DLL project Manages and monitors a specific type of resource (application). The name of this project is the name you give to the Cluster Resource Type project.

  • Cluster Administrator extension DLL Loaded by the Cluster Administrator to allow resources (applications) of this new type to be configured. This DLL project is a COM, in-process server. The name of this project has the letters "Ex" appended to the name you give to the Cluster Resource Type project.

The Microsoft Cluster Server is available with Windows NT Server, Enterprise Edition.

For more information on the Microsoft Cluster Server:

  1. Go to http://www.microsoft.com/ntserver.

  2. Select Product Guide.

  3. Select Technical papers.

  4. Select Enterprise Services.

For more information on how to create a Microsoft Cluster Resource Type application, see Using the Resource Type AppWizard or see the help file that is available in steps 1 and 2 of the wizard.

For more information, see Cluster Server Concepts and Architecture in the Platform SDK.


Details: Beginning Your Program

Home | Overview | How Do I

The following topics provide more detailed information that may be of use when you are beginning your Visual C++ program.

What do want to know more about?

  • Topics related to beginning your program

  • Build settings generated when you create a new program

  • Files created when you create a new program

  • AppWizard language support for Far East languages

  • Excluding files when dependency checking

  • Updating dependencies in a project

  • Using subprojects

  • Creating a custom AppWizard that helps others in your work environment begin their programs


Related Topics: Beginning Your Program

Home | Overview | How Do I | Details

While the Beginning Your Program topics in the Visual C++ Programmer’s Guide cover ways to begin writing Windows programs in C or C++, other areas of the Visual C++ Programmer’s Guide provide information on other aspects of your program.

Click a topic below to find detailed information.

  • Adding user interface features

  • Adding program functionality

  • MFC

  • Sample MFC programs

  • Dynamic Link Libraries (DLLs)

  • ActiveX Controls

  • Internet Server (ISAPI) Extensions or Filters

  • Projects

  • Contents of the Platform SDK

  • External Makefiles

  • Build settings generated when you create a new program


Build Settings Generated When You Create a Visual C++ Program

Home | Overview | How Do I | Details | Sample

Build settings are automatically generated for your Visual C++ program, whenever you create one either by using a wizard (such as the MFC AppWizard) or one of the icons (such as the Application icon) available on the Projects tab of the New dialog.

To view, change, or reset the build settings for your program: from the Project menu, click Settings and then click the C/C++ tab.

Which type of program do you want to know the build settings for?

  • An MFC EXE program

  • An MFC DLL

  • A Win32 program

  • A Win32 DLL

  • A Static library

  • A Console program


Build Settings for an MFC EXE Program

Home | Overview | How Do I | Details | Sample

The following C/C++ settings are the default MFC AppWizard EXE settings that are common for each type of project.

Common Compiler Debug Settings

/nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fp"Debug/projname.pch"

The exceptions to the above are that static lib has /Z7 instead of /Zi and console applications do not use the define /D “_WINDOWS”.

Common Compiler Release Settings

/nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/projname.pch"

The exception to the above is that console applications do not use the define /D “_WINDOWS”.

Common Linker Debug Settings

/nologo /subsystem:windows /incremental:yes /pdb:"Debug/projname.pdb" /debug /machine:I386 /out:"Debug/projname.exe"

Console applications will have the /subsystem:console option set. The settings for the /machine option are determined by your machine type.

Common Linker Release Settings

/nologo /subsystem:windows /incremental:no /pdb:"Release/projname.pdb" /machine:I386 /out:"Release/projname.exe" /out:"Debug/projname.exe"

Console applications will have the /subsystem:console option set. The settings for the /machine option are determined by your machine type.

What do you want to know more about?

  • How do I build my program?


Build Settings for an MFC DLL

Home | Overview | How Do I | Details | Sample

The project settings that the MFC AppWizard (DLL version) sets for DLLs are almost the same as for the MFC AppWizard (EXE version). The following table describes the compiler options and preprocessor defines that the MFC AppWizard sets that distinguishes DLLs from EXEs and distinguishes each kind of MFC DLL from each other.

Kind of DLL | Compiler options | Preprocessor defines
Regular, statically linked to MFC | /MT or /MTd | _WINDLL _USRDLL
Regular, using the shared MFC DLL | /ML or /MLd | _WINDLL _USRDLL _AFXDLL
Extension DLL | /MD or /MDd | _WINDLL _AFXDLL _AFXEXT

The preprocessor defines identify the kind of MFC DLL that you are building. The /MD, /MT, and /ML options determine whether the DLL being built has single-thread support (/MD), multithread support (/MT), or uses the shared MFC DLL (/ML) option.

It is usually best to use the MFC AppWizard (DLL version) default option /MD or /MT when building a DLL. These options support multithread applications. When you specify the /ML option, your DLL will work only when called by single-thread applications. A multithread application that calls a DLL without multithread awareness is likely to fail. Therefore, don’t specify the /ML option unless you know that it will be used only by single-thread applications.

The MFC AppWizard (DLL version) sets the Link option /DLL for all three kinds of MFC DLLs. The /DLL option causes the linker to build a DLL and do the following:

  • Look for the DllMain function in the source code.

  • Link with DLL startup code that performs some initialization for you.

  • Produce an import library for applications using your DLL to link with.

Note that the MFC AppWizard (DLL version) does not set the /DEF option; this option is for use only on the command line. If a .DEF has been added to the project, the linker will use it automatically.

What do you want to do?

  • Learn more about DLLs

  • Create an MFC DLL

  • Learn about the classes and functions AppWizard generates for MFC DLLs

  • Learn how to build my program


Build Settings for non-MFC Programs

Home | Overview | How Do I | Details | Sample

The build settings for a Win32 (non-MFC) program for Windows are almost the same as for MFC-based executables. In the following, projname is the name that is created based on the project name you supply. These are the default compiler options for new application projects:

Debug

/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fp"Debug/projname.pch" /YX /Fo"Debug/" /Fd"Debug/" /c

Release

/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/winapp.pch" /YX /Fo"Release/" /c

Linking

The default link options and link libraries for a Win32 application are:

kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows

If you are using an external makefile, you can use the default build settings as a guide for the settings to use in your makefile.

What do you want to know more about?

  • What are the build settings for an MFC program?

  • What are the build settings for a Win32 DLL?

  • What files are created for a new program?

  • How do I build my program?


Build Settings for a Win32 DLL

Home | Overview | How Do I | Details | Sample

The project settings for Win32 DLLs are almost the same as for Win32 EXEs. In the following, projname is the name that is created based on the project name you supply. Following are the default compiler options for new Win32 DLL projects:

Debug

/nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fp"Debug/projname.pch" /YX /Fo"Debug/" /Fd"Debug/" /c

Release

/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/projname.pch" /YX /Fo"Release/" /c

The default link options and link libraries for Win32 DLLs are:

kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll

If you are using an external makefile, you can use the default build settings as a guide for the settings to use in your makefile.

What do you want to know more about?

  • What are the build settings generated for a Win32 EXE?

  • What files are created for a new program?

  • How to build my program


Build Settings for a Static Library

Home | Overview | How Do I | Details | Sample

The following build settings are generated for static libraries. Projname is the name that is created based on the project name you supply.

Debug

/nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fp"Debug/projname.pch" /YX /Fo"Debug/" /Fd"Debug/" /c

Release

/nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fp"Release/projname.pch" /YX /Fo"Release/" /c

The default LIB options for static libraries are:

Debug

/nologo /out:"Debug\projname.lib"

Release

/nologo /out:"Release\projname.lib"

If you are using an external makefile, you can use the default build settings as a guide for the settings to use in your makefile.

What do you want to know more about?

  • What files are created for a new program?

  • How to build my program


Build Settings for a Console Program

Home | Overview | How Do I | Details | Sample

The C/C++ Project Settings for console applications are almost the same as for other executables. In the following, projname is the name that is created based on the project name you supply. Following are the default compiler options for new console application projects:

Debug

/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /Fp"Debug/projname.pch" /YX /Fo"Debug/" /Fd"Debug/" /c

Release

/nologo /ML /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /Fp"Release/projname.pch" /YX /Fo"Release/" /c

Linking

The default link options and link libraries for console applications are:

kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console

If you are using an external makefile, you can use the default build settings as a guide for the settings to use in your makefile.

What do you want to know more about?

  • What files are created for a new program?

  • How to build my program


File Types Created for Visual C++ Projects

Home | Overview | How Do I | Details

Starter files are automatically generated for your Visual C++ project, whenever you create one either by using a wizard (such as the MFC AppWizard or the ActiveX ControlWizard) or one of the icons (such as the Application icon) available on the Projects tab of the New dialog.

This topic describes all the types of files that are associated with Visual C++ projects. The actual files included in your project will depend on the project type and the options you select when using a wizard. PROJNAME represents the name of your project.

What kind of files do you want to know more about?

  • Project Files and Makefiles

  • Program or Control source and header files

  • Precompiled header files

  • Resource files

  • Help files

  • Other file options

Project Files and Makefiles

PROJNAME.DSW

This is the workspace file used within the development environment. It organizes all the projects into a single workspace.

PROJNAME.OPT

This is the workspace options file used within the development environment. It stores all the user options you create for your workspace, so that each time you open the project workspace it has the look and feel you want and includes any customizations you have made.

PROJNAME.DSP

This is the project file used within the development environment. In previous versions of Visual C++ this file extension was .MAK. It stores the information specific to your project. There will be a separate .DSP file for each project you create. .DSP files are not compatible with NMAKE. You must export a makefile to build with NMAKE.

PROJNAME.CLW

This file is used by ClassWizard to store information about the classes in your project

PROJNAME.ODL

This file contains the Object Description Language source code for a control type library. This file is used by Visual C++ to generate a type library. The generated library exposes the control’s interface to other Automation clients.

PROJNAME.NCB This is the No compile Browser file. It contains information generated by the parser which is used by ClassView, WizardBar, and Component Gallery. If the file is accidentally or deliberately deleted, it is automatically regenerated.

README.TXT A file (located in the parent directory of the project) that describes each file in your project using the actual filenames created by AppWizard or ControlWizard.

Program or Control Source and Header Files

PROJNAME.H

This is the main include file for the program or DLL. It contains all global symbols and #include directives for other header files. It derives the CPrjnameApp class from CWinApp and declares an InitInstance member function. For a control, the CPrjnameApp class is derived from COleControlModule.

PROJNAME.CPP

This file is the main program source file. It creates one object of the class CPrjnameApp (which is derived from CWinApp) and overrides the InitInstance member function.

For executables, CPrjnameApp::InitInstance does several things. It registers document templates, which serve as a connection between documents and views, creates a main frame window, and creates an empty document (or opens a document if one is specified as a command-line argument to the application).

For DLLs and ActiveX (formerly OLE) controls, CProjNameApp::InitInstance registers the control’s object factory with OLE by calling COleObjectFactory::RegisterAll and makes a call to AfxOLEControlInit. In addition, the member function CProjNameApp::ExitInstance is used to unload the control from memory with a call to AfxOleControlTerm.

This file also registers and unregisters the control in the Windows registration database by implementing the DllRegisterServer and DllUnregisterServer functions.

PROJNAMECTL.H, PROJNAMECTL.CPP

These files declare and implement the CProjnameCtrl class. CProjnameCtrl is derived from COleControl, and skeleton implementations of some member functions are defined that initialize, draw, and serialize (load and save) the control. Message, event, and dispatch maps are also defined.

PROJNAMEDLG.CPP, PROJNAMEDLG.H

These files are created if you choose a dialog-based application. The files derive and implement the dialog class, named CProjnameDlg, and include skeleton member functions to initialize a dialog and perform dialog data exchange (DDX). Your About dialog class is also placed in these files instead of in PROJNAME.CPP.

DLGPROXY.CPP, DLGPROXY.H

in a dialog-based program, these are the implementation and header file for the project’s Automation proxy class for the main dialog. This is only used if you have chosen Automation support. This file is one of the templates provided by MFCAPWZ.DLL.

PROJNAMEDOC.CPP, PROJNAMEDOC.H

These files derive and implement the document class, named CProjnameDoc, and include skeleton member functions to initialize a document, serialize (save and load) a document, and implement debugging diagnostics.

PROJNAMESET.H/.CPP These files are created if you create a program that supports a database and contains the recordset class.

PROJNAMEVIEW.CPP, PROJNAMEVIEW.H

These files derive and implement the view class, named CProjnameView, that is used to display and print the document data. The CProjnameView class is derived from CEditView, CFormView, CRecordView, CDaoRecordView, CTreeView, CListView, CRichEditView, CScrollView, or CView and has skeleton member functions to draw the view and implement debugging diagnostics. If you have enabled support for printing, message-map entries are added for print, print setup, and print preview command messages. These entries call the corresponding member functions in the base view class.

PROJNAMEPPG.H, PROJNAMEPPG.CPP

These files declare and implement the CProjnamePropPage class. CProjnamePropPage is derived from COlePropertyPage and a skeleton member function, DoDataExchange, is provided to implement data exchange and validation.

IPFRAME.CPP, IPFRAME.H

These files are created if the Mini-Server or Full-Server option is selected in AppWizard’s Automation Options page (step 3 of 6). The files derive and implement the in-place frame window class, named CInPlaceFrame, used when the server is in-place activated by a container program.

MAINFRM.CPP, MAINFRM.H

These files derive the CMainFrame class from either CFrameWnd (for SDI applications) or CMDIFrameWnd (for MDI applications). The CMainFrame class handles the creation of toolbar buttons and the status bar, if the corresponding options are selected in AppWizard’s Application Options page (step 4 of 6).

CHILDFRM.CPP, CHILDFRM.H

These files derive the CChildFrame class from CMDIChildWnd. The CChildFrame class is used for MDI document frame windows. These files are always created if you select the MDI option.

Precompiled Header Files

STDAFX.CPP, STDAFX.H

These files are used to build a precompiled header file PROJNAME.PCH and a precompiled types file STDAFX.OBJ. It is important that you neither define nor undefine any of the _AFX_NO_XXX macros in stdafx.h. See the Knowledge Base article "PRB: Problems Occur When Defining _AFX_NO_XXX". You can find Knowledge Base articles on the MSDN Library CD, or at http://www.microsoft.com/kb/.

Resource Files

PROJNAME.RC, RESOURCE.H

This is the resource file for the project and its header file. The resource file contains the default menu definition and accelerator and string tables for a generic MFC application. It also specifies a default About box and an icon file (RES\PROJNAME.ICO). The resource file includes the file AFXRES.RC for standard Microsoft Foundation class resources. If toolbar support has been specified as an option, it also specifies the toolbar bitmap file (RES\TOOLBAR.BMP).

PROJNAME.RC2

The RC2 file can be included at the top of the RC file in a project. An RC2 file is useful for including resources used by several different projects. Instead of having to create the same resources several times for different projects, you can put them in an RC2 file and include the RC2 file into the main RC file.

PROJNAME.DEF

If the project is for a DLL, this is the module-definition file for the project. For a control it provides the name and description of the control, as well as the size of the run-time heap.

RES\PROJNAME.ICO

This is the icon file for the MFC program or control. This icon appears when the application is minimized and is also used in the About box.

RES\TOOLBAR.BMP

This bitmap file is used to represent your program or control in a toolbar or palette. This bitmap is included in the project’s resource file. The initial toolbar and status bar are constructed in the CMainFrame class.

Help File Option

MAKEHELP.BAT

This batch file (located in the parent directory) is provided only for backward compatibility with older projects. In Visual C++ 6.0, custom build rules are now attached to the .hpj, .cnt and resource.h files, making makehelp.bat obsolete.

This file is used to create the help file PROJNAME.HLP for your program or control.

PROJNAME.HPJ

This file (located in the parent directory) is the Help project file used by the Help compiler to create your program or control’s Help file.

PROJNAME.RTF

This Help file (located in the HLP subdirectory) contains template topics that you can edit and information on customizing your .HPJ file.

PROJNAME.CNT

This file provides the structure for the Contents window in Windows Help.

PRINT.RTF

This file, created if printing support is selected (which it is by default), describes the printing commands and dialog boxes.

BULLET.BMP

This bitmap is used by standard Help file topics to represent bulleted lists.

Other File Options

PROJNAME.LIC

This is the user license file. This file must be present in the same directory as the program or DLL to allow an instance of the control to be created in a design-time environment. Typically, you will distribute this file with a control, but your customers will not distribute it.

PROJNAME.REG

This file is created in two cases. (1) You have selected any Automation server option or an Automation option. (2) You have selected a document file extension (one of the options available in the Advanced Options dialog). The file demonstrates the kind of registration settings the framework will set for you.

RES\ITOOLBAR.BMP

This file is created only if you have chosen any Automation server support and have also chosen the Dockable Toolbar option. The file contains tiled images for the toolbar when the server application is in-place activated inside a container application. The file is similar to the standard RES\TOOLBAR.BMP except that many nonserver commands are removed.


AppWizard Language Support for Far East Languages

Home | Overview | Details

Visual C++ allows you to choose different languages when you create an MFC AppWizard program. The Far East language support DLLs (Japanese, Korean, and simplified Chinese) for the MFC AppWizard, which require double-byte enabled operating systems, are not installed by default. Thus you will not see them in the language drop-down list on the first page of the MFC AppWizard. However, you can find them in the Microsoft Visual Studio\Common\msdev98\bin\ide directory on the Visual C++ CD as follows:

Language | AppWizard DLL
Japanese | APPWZJPN.DLL
Korean | APPWZKOR.DLL
Chinese (simplified) | APPWZCHS.DLL

To take advantage of Far East language support:

  1. Copy the appropriate MFC AppWizard DLL to your Microsoft Visual Studio\Common\msdev98\bin\ide directory. This DLL can be found in the corresponding directory on Visual C++ CD.

  2. Install the appropriate code page on your system.

    If your application is dynamically linked to MFC, you must have the corresponding localized version of the MFC resource DLL, MFC40LOC.DLL, in your Windows system directory. To do this, copy the corresponding DLL in the MFC\include\L.XXX\MFC40XXX.DLL on Visual C++ CD into the Windows system directory, and rename it to be MFC40LOC.DLL. For more information on using the localized resources that Visual C++ provides, see Tech Note 56 and Tech Note 57.

    – or–

    If your application is statically linked to MFC, you must have the appropriate localized MFC resource files in your MFC\[src|include]\L.XXX\*.rc directory. You can find these files in the corresponding directories of Visual Studio CD1. For more information on using the localized resources that Visual C++ provides, see Tech Note 56 and Tech Note 57.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.


Excluding Files When Dependency Checking

Home | Overview | How Do I | Details

Two exclusion files are used for dependency checking. Adding files to the exclusion files speeds up dependency checking.

The file lists in the exclusion files should contain only files that are not likely to change often. Whenever dependencies are updated, the files in these lists are excluded from dependency scanning and does not display them in the External Dependencies folder.

If you change only files in either of these lists, you must click Rebuild All from the Build menu in order to build your selected project. If you click Build, and the External Dependencies folder has no changes in it, you will get a message reporting that your project is up to date. Alternatively, you could select the source files that include the changed dependencies, and click Compile from the shortcut menu in order to explicitly build those files. After those files have been built, click Build from the Build menu to build the project.

The following two exclusion files are referenced:

SYSINCL.DAT

Contains a default list of system include files, is installed by the setup program on your computer in the directory in which you installed MSDEV.EXE.

MSVCINCL.DAT

A text file that you can create and put in your Windows directory. You can list in it additional files that you want to exclude, such as headers for external class libraries or some of the include files in a large project. You should use this file for additions because SYSINCL.DAT may be overwritten if you reinstall Visual C++, if you modify your installation with Setup, or if you update your installation. If you use the text editor to create this file, you must exit and then restart it for the file to become effective.

Whenever you close the Files Into Project dialog box, the files in your project are scanned for dependencies. Any files found that are not already explicitly added to the project are added to the Dependencies folder for each project you’ve added files to.

If you move or copy selections that include files in the External Dependencies folder, only the source files are moved or copied. Dependencies are updated before the project is built, however, and they appear in the appropriate folders.

What do you want to know more about?

  • Updating dependencies in a project

  • Using Subprojects


Updating Dependencies in a Project

Home | Overview | Details

Dependencies are updated every time the project is built using either Build, Rebuild All, or Batch Build. Dependencies for C and C++ files are generated by the C/C++ compiler during the build process. Dependencies for other types of source files are generated by the build system's dependency scanner.

Using Update All Dependencies causes the compiler generated dependencies to be read and non C/C++ source files to be scanned for dependencies. Therefore, the dependency information for C/C++ files will not reflect any changes made since the last build.

To update the dependencies

  1. On the Build menu, click Update All Dependencies.

  2. In the Update All Dependencies box, select the project you want to update the list for.

Note The External Dependencies folder in the FileView window of the project workspace is also updated after each build or if you choose Update All Dependencies.

What do you want to know more about?

  • Excluding files when dependency checking

  • Using Subprojects


Using Subprojects in Visual C++

Home | Overview | Details

A subproject establishes a dependency of one Visual C++ project on another within a workspace file. You will want to create a subproject whenever you want to link two separate projects together.

For example, when a project builds an MFC executable program that depends on a static library. If the static library is a subproject of the project that builds the executable program, then the library will be updated before the executable program is built. Each configuration of a subproject is made a dependency of the corresponding configuration in the containing project. Building a configuration of the executable program also builds the same configuration of the subproject.

What do you want to know more about?

  • How to create a subproject

  • Excluding files when dependency checking

  • Updating dependencies in a project


AppWizard Programming Reference

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

MFCAPWZ.DLL contains the code that controls the default behavior of the MFC AppWizard. It also contains the code that controls the interactions between the MFC AppWizard and any custom AppWizards you create. This reference describes the programming interface to MFCAPWZ.DLL. You can use the interface to add functionality to the default behavior of your custom AppWizard. For more information, see the descriptions of the items in the following table.

Statements | Description
NEWPROJ.INF Statements | The syntax for and behavior of the statements that MFCAPWZ.DLL uses to generate a project.

AppWizard C++ Classes | Description
CappWizStepDlg | The class from which custom AppWizard steps are derived.
CcustomAppWiz | The class that provides communication services between MFCAPWZ.DLL and your custom AppWizard.
OutputStream | The class that wraps two member functions used to write custom resource templates to an output stream.

AppWizard C Functions | Description
C Functions Exported by MFCAPWZ.DLL | MFCAPWZ.DLL and your custom AppWizard use these C functions to communicate.

AppWizard Macros | Description
The Dictionary | Storage location for both your macros and the standard MFC AppWizard macros.
Standard MFC AppWizard Macros | Macros that track the choices an AppWizard user makes from the Projects tab of the New dialog box, and from AppWizard’s steps. MFCAPWZ.DLL uses many of the same macros to track the choices that a custom AppWizard user makes from the Projects tab of the New dialog box.

Custom Resource Templates | Description
Custom Resource Templates | The building blocks that MFCAPWZ.DLL and a finished custom AppWizard use to create a final application. You can create and add your own custom resource templates to your custom AppWizard project.
Standard Custom Resource Templates | The templates that MFCAPWZ.DLL and the DLLs containing localized resources, those with names that take the form APPWZ*.DLL, use to build the files and user-interface components that compose a project.

AppWizard Directives | Description
Standard MFC AppWizard Directives | Directives, such as $$IF, $$ELIF, $$ELSE, $$ENDIF, $$INCLUDE, $$BEGINLOOP, $$ENDLOOP, and $$SET_DEFAULT_LANG used by MFCAPWZ.DLL to generalize its custom resource templates so that the templates can be used for multiple project types. You will probably need to use these directives when you write a custom AppWizard.

See Also Overview of Creating a Custom AppWizard, Adding Functionality to Your Custom AppWizard, CAppWizStepDlg, CCustomAppWiz, OutputStream, C Functions Exported by MFCAPWZ.DLL, The Dictionary, Standard AppWizard Macros, Understanding Custom Resource Templates, Standard Custom Resource Templates, Understanding CONFIRM.INF and NEWPROJ.INF


NEWPROJ.INF Statements

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

NEWPROJ.INF contains statements that MFCAPWZ.DLL reads to determine a project structure. A statement in NEWPROJ.INF can use either of the following two forms of syntax:

/directory

This statement directs MFCAPWZ.DLL to create a subdirectory of the Visual C++ project directory. Note that the slash is a forward slash, not a backslash. This is how, for example, AppWizard creates a separate RES subdirectory under the project directory, and how the custom AppWizard project type creates its TEMPLATE subdirectory.

–or–

[flags]template-name tab-character destination-filename

This statement directs MFCAPWZ.DLL to use a custom resource template named template-name to generate a file named by destination-filename. If destination-filename includes a path, all directories on the path must exist. Remember that you can use the /directory statement to create a directory. You generate the tab-character by pressing the TAB key.

flags

A flag is any of three optional characters defined in the table below. They can appear in any order and any combination, but must appear immediately before template-name. No characters (not even whitespace) can separate the flags from each other or from template-name. By default, a file appearing in NEWPROJ.INF is added to the project. If a - flag precedes the file, it is not added.

Template Name Flags

Flag Description
= Copies the template, verbatim, to destination-filename. This flag tells MFCAPWZ.DLL to use CopyTemplate rather than ProcessTemplate. ProcessTemplate is the default.

For example, the following line causes MFCAPWZ.DLL to call CopyTemplate to copy the project’s icon directly to the project:

=ROOT.ICO  $$root$$.ico

Note that using the lowercase version of the $$root$$ macro causes the generated filename to be lowercase. For more information on the root macro, see The Projects Tab on the New Dialog Box Options.
- Specifies that the file should not be added to the project.

!

 Specifies that the file should be marked exclude from build. This forces the build system to ignore the file during a build of the project.
? Specifies that the file should be treated as a Help file. This puts the file in the “Help Files” folder in the FileView tab of the project workspace window.
: Specifies that the file should be treated as a resource file. This puts the file in the “Resource Files” folder in the FileView tab of the project workspace window.
# Specifies that the file should be treated as a template. This flag implies that the ! flag will be used. This puts the file in the “Template Files” folder in the FileView tab of the project workspace window.
* Forces LoadTemplate to use an MFC AppWizard resource rather than a custom AppWizard resource. Use this flag when you want your custom AppWizard to bypass its own template in preference to the MFC AppWizard’s copy. For example, when the Custom AppWizard project type (CUSTMWZ.AWX) generates a custom AppWizard that is based on an existing sequence of MFC AppWizard steps, it needs the MFC AppWizard’s NEWPROJ.INF, not its own. Using this flag is unnecessary in most situations because MFCAPWZ.DLL looks for a template in the MFC AppWizard’s resources if it can’t first find the template in the custom AppWizard’s resources. This flag simply bypasses the initial check in the custom AppWizard’s resources. For example, the following line causes ProcessTemplate to add the MFCAPWZ.DLL version of DLGROOT.CPP to the generated project’s makefile:
 *+DLGROOT.CPP  $$root$$.cpp

Note that using the lowercase version of the $$root$$ macro causes the generated filename to be lowercase. For more information on the root macro, see Projects Tab on the New Dialog Box Options.

template-name

The resource ID of a custom resource template. When an end user clicks OK in the New Project Information dialog box, MFCAPWZ.DLL begins parsing NEWPROJ.INF. For each template-name found in NEWPROJ.INF, MFCAPPWZ.DLL calls LoadTemplate with template-name to load the custom resource template for processing. If template-name is not found, the custom AppWizard displays an error in a message box, stops code generation, and returns to the dialog box from which template parsing began.

destination-filename

Names the file and directory in which MFCAPWZ.DLL generates the file associated with template-name. The named directory must already exist. If it doesn’t, MFCAPWZ.DLL presents a message box to inform you that it can’t generate the file and stops code generation.

See Also Overview of Creating a Custom AppWizard, Understanding the Files That AppWizard Creates, Adding Functionality to Your Custom AppWizard, Understanding CONFIRM.INF and NEWPROJ.INF, CONFIRM.INF, NEWPROJ.INF, Understanding Text Templates, How Macros Get Their Values, How to Specify Macros in Directives or Text


CAppWizStepDlg

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The CAppWizStepDlg class is the class from which custom AppWizard steps are derived. Recall that the AppWizard and custom AppWizard user interface is comprised of nested dialog boxes: an outer one and one or more inner ones. The outer dialog box contains the title bar and the Help, Cancel, Back, Next, and Finish buttons. It serves as a master control panel and also frames the inner dialog box.

The outer dialog box frames an area that can contain one or more dialog boxes called steps. These steps, derived from CAppWizStepDlg, contain controls that allow the MFC AppWizard or a custom AppWizard to gather information from a user.

Each custom AppWizard step is a combination of a dialog template and its associated CAppWizStepDlg-derived class. AppWizard automatically generates a dialog template and a CAppWizStepDlg-derived class for each custom step in your custom AppWizard.

Use the dialog editor to add controls to the dialog template, and then use ClassWizard to add class members representing the controls to the CAppWizStepDlg-derived class.

CAppWizStepDlg is derived from the Microsoft Foundation Class Library (MFC) CDialog class.

Typically, in a custom AppWizard, instances of each CAppWizStepDlg-derived class are constructed when AppWizard (MFCAPWZ.DLL) calls CCustomAppWiz::InitCustomAppWiz and destroyed when AppWizard calls CCustomAppWiz::ExitCustomAppWiz.

See Also Class Members, Overview of Creating a Custom AppWizard, Adding Functionality to Your Custom AppWizard, CAppWizStepDlg Class Members, CCustomAppWiz, OutputStream, C Functions Exported by MFCAPWZ.DLL, The Dictionary, Standard AppWizard Macros, Understanding Custom Resource Templates, Standard Custom Resource Templates, Understanding CONFIRM.INF and NEWPROJ.INF


CAppWizStepDlg Class Members

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Construction

OnDismiss Called whenever a custom AppWizard user chooses the Next, Back, or Finish button. Override in order to create, update, or remove macros from the dictionary through calls to aw.m_Dictionary.

See Also CAppWizStepDlg Overview, Overview of Creating a Custom AppWizard, Adding Functionality to Your Custom AppWizard, CAppWizStepDlg, OnDismiss, CCustomAppWiz, OutputStream, C Functions Exported by MFCAPWZ.DLL, The Dictionary, Standard AppWizard Macros, Understanding Custom Resource Templates, Standard Custom Resource Templates, Understanding CONFIRM.INF and NEWPROJ.INF


CAppWizStepDlg::CAppWizStepDlg

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

CAppWizStepDlg( UINT nIDTemplate );

Parameters

nIDTemplate

Contains the ID number of a dialog box template resource.

Remarks

Accepts a template ID number, usually with an IDD_ prefix (for example, IDD_CUSTOM1) and constructs a resource-based dialog box: a step, in the case of a custom AppWizard.

See Also CAppWizStepDlg Overview, Class Members, Overview of Creating a Custom AppWizard, Adding Functionality to Your Custom AppWizard, CAppWizStepDlg::OnDismiss, CCustomAppWiz, OutputStream, C Functions Exported by MFCAPWZ.DLL, The Dictionary, Standard AppWizard Macros, Understanding Custom Resource Templates, Standard Custom Resource Templates, Understanding CONFIRM.INF and NEWPROJ.INF


CAppWizStepDlg::OnDismiss

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

BOOL OnDismiss( );

Return Value

Nonzero if the dialog box can be dismissed; otherwise 0.

Remarks

A step’s OnDismiss member function is called by MFCAPWZ.DLL whenever a custom AppWizard user performs any action that calls CCustomAppWiz::Next or CCustomAppWiz::Back. A step’s OnDismiss member function is also called if the user clicks Finish.

Typically, you will call UpdateData(TRUE) from OnDismiss to transfer a step’s control values to the appropriate CAppWizStepDlg member variables. You should then use the CCustomAppWiz::m_Dictionary member to transfer the values to the custom AppWizard’s dictionary. The values in the dictionary are the values that the CCustomAppWiz::ProcessTemplate member function uses to map the macros it finds while parsing a custom resource template to their actual values.

If the data is invalid, your custom AppWizard can display a dialog box and return FALSE, in which case MFCAPWZ.DLL will not continue to the next step.

See Also CAppWizStepDlg Overview, Class Members,CCustomAppWiz::Back, CCustomAppWiz::Next, CCustomAppWiz::m_Dictionary, CAppWizStepDlg::CAppWizStepDlg, CCustomAppWiz::ProcessTemplate, CCustomAppWiz, OutputStream, C Functions Exported by MFCAPWZ.DLL


CCustomAppWiz

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The CCustomAppWiz class provides communication services between MFCAPWZ.DLL and your custom AppWizard. MFCAPWZ.DLL calls these member functions. The base-class implementations of the CCustomAppWiz member functions reside in MFCAPWZ.DLL, but your custom AppWizard can override them.

See Also Class Members, CCustomAppWiz::Back, CCustomAppWiz::Next, CCustomAppWiz::m_Dictionary, CCustomAppWiz::CopyTemplate, CCustomAppWiz::CustomizeProject, CCustomAppWiz::ExitCustomAppWiz, CCustomAppWiz::InitCustomAppWiz, CCustomAppWiz::GetPlatforms, CCustomAppWiz::LoadTemplate, CCustomAppWiz::PostProcessTemplate, CCustomAppWiz::ProcessTemplate


CCustomAppWiz Class Members

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Data Members

Back | Moves to the previous step. Called whenever a custom AppWizard user chooses the Back button.
CopyTemplate | Called by MFCAPWZ.DLL to copy verbatim a binary template into the custom AppWizard user’s project.
CustomizeProject | Called by MFCAPWZ.DLL after the project is generated to allow the custom AppWizard to customize the project settings.
ExitCustomAppWiz | Called by MFCAPWZ.DLL just before it unloads the custom AppWizard. ExitCustomAppWiz is a convenient place to perform any cleanup required by the custom AppWizard.
GetPlatforms | Called by MFCAPWZ.DLL immediately after it loads and initializes the custom AppWizard. Override to obtain the list of platforms currently installed for Visual C++ and choose those that your custom AppWizard will support.
InitCustomAppWiz | Called by MFCAPWZ.DLL immediately after it loads the custom AppWizard. InitCustomAppWiz is a convenient place to perform initialization required by the custom AppWizard.
LoadTemplate | Called by MFCAPWZ.DLL to load custom resource templates, such as NEWPROJ.INF and CONFIRM.INF, for further processing.
Next | Moves to the next step. Called whenever a custom AppWizard user chooses the Next button.
PostProcessTemplate | Called by MFCAPWZ.DLL after it finishes parsing a template. PostProcessTemplate is a convenient place for you to deallocate memory that you allocated for a custom resource template. Typically you will not need to override this function.
ProcessTemplate | Called by MFCAPWZ.DLL to process a custom resource template returned by LoadTemplate. ProcessTemplate expands embedded macros, obeys embedded directives, and directs the output to an output stream.

See Also CCustomAppWiz Overview, CCustomAppWiz::Back, CCustomAppWiz::Next, CCustomAppWiz::m_Dictionary, CAppWizStepDlg::CAppWizStepDlg, CCustomAppWiz::CopyTemplate, CCustomAppWiz::CustomizeProject, CCustomAppWiz::ExitCustomAppWiz, CCustomAppWiz::GetPlatforms, CCustomAppWiz::InitCustomAppWiz, CCustomAppWiz::LoadTemplate, CCustomAppWiz::PostProcessTemplate, CCustomAppWiz::ProcessTemplate


CCustomAppWiz::Back

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual CAppWizStepDlg* Back( CAppWizStepDlg* pDlg );

Return Value

A pointer to the previous step. If pDlg points to the first step, Back returns NULL to indicate that MFCAPWZ.DLL should next display the New dialog box Projects tab. For more information on steps, see the class CAppWizStepDlg.

Parameters

pDlg

Pointer to the current step.

Remarks

Back moves to the previous step. AppWizard (MFCAPWZ.DLL) calls this function whenever a user clicks Back. The Back button is located on the main, outer dialog box that MFCAPWZ.DLL displays. For more information on steps and a description of the two-dialog-box structure of the MFC AppWizard and custom AppWizards, see CAppWizStepDlg.

Before Back is called, MFCAPWZ.DLL calls the CAppWizStepDlg::OnDismiss member function of the currently displayed step. You override CAppWizStepDlg::OnDismiss to transfer data from the step’s controls to the appropriate variables and to update the appropriate dictionary values. If your custom AppWizard returns FALSE from the call to the overridden CAppWizStepDlg::OnDismiss, then the current step remains active, and Back is not called.

See Also Class Members, CCustomAppWiz::Next, CAppWizStepDlg::OnDismiss, CAppWizStepDlg::CAppWizStepDlg


CCustomAppWiz::CopyTemplate

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual void CopyTemplate( LPCTSTR lpszInput, DWORD dwSize, OutputStream* pOutput );

Parameters

lpszInput

A pointer, returned by CCustomAppWiz::LoadTemplate, to a custom resource template.

dwSize

The size of the custom resource template. Provided by the LoadTemplate function’s rdwSize argument.

pOutput

A pointer to the stream that represents the destination of the output from CCustomAppWiz::CopyTemplate.

Remarks

CopyTemplate copies a binary template (a type of custom resource template) verbatim into the end user’s project.

See Also Class Members, CCustomAppWiz::LoadTemplate, CCustomAppWiz::ProcessTemplate, CCustomAppWiz::PostProcessTemplate, Understanding Custom Resource Templates, Understanding Binary Templates


CCustomAppWiz::CustomizeProject

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual void CustomizeProject(IBuildProject* pProject)

Parameters

pProject A pointer to the BuildProject object. You may access methods and properties on the BuildProject object through this pointer to customize the project settings.

Remarks

AppWizard (MFCAPWZ.DLL) calls the CustomizeProject member function just after generating all of the files and creating the project.

CustomizeProject provides a place for you to customize the settings of the project. For example, you can adjust the compiler and linker settings, and add custom build steps that execute after the target is built. For details on what aspects of the project may be customized, see BuildProject and Configuration.

It is important to note that IBuildProject and all interfaces you can get from it (such as IConfiguration) are COM interfaces. You must be careful to release all interfaces you acquire (by calling the Release() method on each of those interfaces). In accordance with the standard rules of COM, you must not release pProject, unless you explicitly call AddRef on it, since pProject is passed as an "in" parameter to this function.

See Also Class Members, CCustomAppWiz::InitCustomAppwiz


CCustomAppWiz::ExitCustomAppWiz

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual void ExitCustomAppWiz( );

Remarks

AppWizard (MFCAPWZ.DLL) calls ExitCustomAppWiz just before it unloads your custom AppWizard from memory. Use ExitCustomAppWiz to perform any cleanup necessary, such as deallocating instances of each of your custom AppWizard’s CAppWizStepDlg-derived steps. The base-class version of ExitCustomAppWiz does nothing.

See Also Class Members, CCustomAppWiz::InitCustomAppwiz


CCustomAppWiz::GetPlatforms

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual void GetPlatforms( CStringList& rPlatforms );

Parameters

rPlatforms

A reference to a CStringList of each platform currently installed. Platform names that rPlatforms can contain are shown in the following table.

Platform name | Comes with
Win32 (x86) | Visual C++
Win32 (MIPS) | Visual C++ RISC edition
Win32 (ALPHA) | Visual C++ RISC edition
Win32 (PowerPC) | Visual C++ RISC edition

Remarks

The GetPlatforms member function allows you to specify which operating-system and hardware platforms your custom AppWizard will support. MFCAPWZ.DLL calls this function with a list containing an entry for each platform currently installed. You override GetPlatforms to parse and modify this list. Typically, you will remove those platform names from the list that your custom AppWizard does not support.

The MFC AppWizard calls GetPlatforms after loading and initializing a custom AppWizard. It uses the platform names in rPlatforms, which are always in English, to determine which platform names will appear in your custom AppWizard’s Platforms checklist. For each English name in rPlatforms, the MFC AppWizard places a locale-specific platform name into your custom AppWizard’s Platforms checklist.

For each platform selected by the custom AppWizard user, MFCAPWZ.DLL sets a corresponding target macro in the dictionary and removes those for the nonselected platforms.

The following example shows how to traverse a platforms list and remove all strings that don’t start with “Win32”, thus keeping the Intel® Win32, MIPS Win32, and ALPHA Win32 as target platforms.

// This custom AppWizard only targets Win32 platforms
void CSampleAppWiz::GetPlatforms(CStringList& rPlatforms)
{
   POSITION pos = rPlatforms->GetHeadPosition();
   while (pos != NULL)
   {
      POSITION posCurr = pos;
      CString strPlatform=rPlatforms->GetNext(pos);
      if (strPlatform.Left(5) != _T("Win32"))
         rPlatforms->RemoveAt(posCurr);
   }
}

If you do not override GetPlatforms, MFCAPWZ.DLL will display the names of all of the currently loaded platforms in the Platforms checklist.

See Also Class Members, target macro, The Dictionary


CCustomAppWiz::InitCustomAppWiz

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual void InitCustomAppWiz( );

Remarks

The MFC AppWizard (MFCAPWZ.DLL) calls the InitCustomAppWiz member function just after loading a custom AppWizard. This occurs immediately after a custom AppWizard user has selected your custom AppWizard from the list on the Projects tab in the New dialog.

This function provides a place for you to perform any initialization required by the custom AppWizard, such as setting internal structures to default values and allocating an instance of each CAppWizStepDlg class. These instances will later be returned to the MFC AppWizard when it calls your custom AppWizard’s Next and Back functions.

You can also override default MFC AppWizard settings in InitCustomAppWiz by modifying the contents of the dictionary. For example, if your company or customer requires that context-sensitive help be a default feature, you can add “HELP” to the dictionary, from within InitCustomAppWiz, and cause the MFC AppWizard’s Context-Sensitive Help check box to be selected by default. This example, of course, assumes that your custom AppWizard uses the relevant standard MFC AppWizard step and associated templates.

The base-class version of InitCustomAppWiz does nothing.

A custom AppWizard creates an executable file by default. If your custom AppWizard creates a DLL, set the standard AppWizard macro “PROJTYPE_DLL” in the InitCustomAppWiz function as follows:

YourProjectNameaw.m_Dictionary[“PROJTYPE_DLL“] = “1“;

This code informs MFCAPWZ.DLL to create a project makefile that builds a DLL rather than an executable file. The MFC AppWizard (MFCAPWZ.DLL) automatically generates this code if you create a custom AppWizard based on the standard MFC AppWizard steps for creating a DLL. Note that MFCAPWZ.DLL only checks that “PROJTYPE_DLL” exists and has a value, the actual macro value is not important unless your custom AppWizard requires that it have meaning.

See Also CCustomAppWiz Overview, Class Members, CCustomAppWiz::ExitCustomAppwiz, CCustomAppWiz::Back, CCustomAppWiz::Next, The Dictionary, CAppWizStepDlg::CAppWizStepDlg


CCustomAppWiz::LoadTemplate

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual LPCTSTR LoadTemplate( LPCTSTR lpszTemplateName, DWORD& rdwSize, HINSTANCE hInstance = NULL );

Return Value

A pointer to the loaded custom resource template for use by CCustomAppWiz::CopyTemplate or CCustomAppWiz::ProcessTemplate.

Parameters

lpszTemplateName

A pointer to a string that contains the name (such as “NEWPROJ.INF” or “RESOURCE.H”) of a custom resource template. The custom resource has a type of “TEMPLATE”.

rdwSize

The size of the custom resource template is returned in this parameter. LoadTemplate provides this value for use by CCustomAppWiz::CopyTemplate and CCustomAppWiz::ProcessTemplate.

hInstance

A pointer that can either be NULL or be the handle of a Win32 module (a DLL or executable file) that you specify. In either case, hInstance informs LoadTemplate where it can find the custom resource template named by lpszTemplateName.

Remarks

After the user clicks OK in the custom AppWizard’s New Project Information dialog box, LoadTemplate finds, locks, and loads into memory the custom resource of type “TEMPLATE” that is named by lpszTemplateName.

If hInstance is NULL, the base-class implementation of LoadTemplate first looks in your custom AppWizard’s DLL for the custom resource template named by lpszTemplateName, and then, if the template is not there, among the MFC AppWizard’s custom resource templates. If hInstance is not NULL, the base-class implementation of LoadTemplate looks in the Win32 module hInstance.

You can override LoadTemplate to load templates from sources other than your custom AppWizard’s DLL or the MFC AppWizard DLLs. For more information on this process, see the implementation of LoadTemplate in the sample code for CUSTMWZ.AWX in the Microsoft Visual Studio\Common\msdev98\bin\ide directory.

See Also CCustomAppWiz Overview, Class Members, CCustomAppWiz::CopyTemplate, CCustomAppWiz::ProcessTemplate, CCustomAppWiz::PostProcessTemplate, Understanding Custom Resource Templates, Understanding Text Templates


CCustomAppWiz::Next

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual CAppWizStepDlg* Next( CAppWizStepDlg* pDlg );

Return Value

A pointer to the next step.

If pDlg is NULL, your custom AppWizard should return a pointer to Step 1. This default action, provided by CUSTMWZ.AWX, occurs when the user clicks OK from the Projects tab of the New dialog box.

If pDlg is the last step, your custom AppWizard should return NULL. This default action, provided by CUSTMWZ.AWX, occurs if SetNumberOfSteps is called incorrectly or if your project is based on an existing project. In the first case, MFCAPWZ.DLL assumes that there are no more steps and displays the New Project Information dialog box. In the second case, no steps are required, and the code provided by CUSTMWZ.AWX for Next adds project- and class-name macros to the dictionary.

For more information on steps, see CAppWizStepDlg.

Parameters

pDlg

Pointer to the current step, or NULL if the custom AppWizard user has chosen the Create button from either the New Project Workspace or Insert Project dialog box.

Remarks

Next moves to the next step. AppWizard (MFCAPWZ.DLL) calls this function whenever a user chooses either Next or OK. The Next button is located on the main, outer dialog box that MFCAPWZ.DLL displays. The OK button is located on the Projects tab of the New dialog box. If there is no next step, Next is inactive. For more information on steps and a description of the two-dialog-box structure of AppWizard and custom AppWizards, see CAppWizStepDlg.

Before Next is called, MFCAPWZ.DLL calls the CAppWizStepDlg::OnDismiss member function of the currently displayed step. You override OnDismiss to transfer data from the step’s controls to the appropriate variables and to update the appropriate dictionary values. If your custom AppWizard’s call to OnDismiss returns FALSE, then the step remains active, and Next is not called.

See Also CCustomAppWiz Overview, Class Members, The Dictionary, SetNumberOfSteps, CCustomAppWiz::Back, CAppWizStepDlg::OnDismiss


CCustomAppWiz::PostProcessTemplate

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual void PostProcessTemplate( LPCTSTR szTemplate );

Parameters

szTemplate

A pointer to a template.

Remarks

If you override CCustomAppWiz::LoadTemplate to load a custom resource template into memory (one that isn’t stored in the MFC AppWizard’s DLLs or your custom AppWizard’s DLL), PostProcessTemplate provides a convenient place for you to deallocate the custom resource template’s memory. MFCAPWZ.DLL calls PostProcessTemplate after it finishes parsing a custom resource template.

See Also CCustomAppWiz Overview, Class Members, Understanding Custom Resource Templates, CCustomAppWiz::LoadTemplate, CCustomAppWiz::CopyTemplate, CCustomAppWiz::ProcessTemplate


CCustomAppWiz::ProcessTemplate

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

virtual void ProcessTemplate( LPCTSTR lpszInput, DWORD dwSize, OutputStream* pOutput );

Parameters

lpszInput

A pointer, returned by CCustomAppWiz::LoadTemplate, to a custom resource template.

dwSize

The size of the custom resource template. Provided by the LoadTemplate function’s rdwSize argument.

pOutput

A pointer to the stream that represents the destination of the output from ProcessTemplate.

Remarks

ProcessTemplate accepts a string, which is a custom resource template returned by LoadTemplate, parses the string, and passes the string back to MFCAPWZ.DLL through an output stream (pOutput).

When ProcessTemplate parses the string, it expands macros and obeys the MFC AppWizard directives. The result is usually a source file (such as an .H, .CPP, or .RC file) that can be placed directly into the structure of a new project or is a CONFIRM.INF file or a NEWPROJ.INF file. For more information on template parsing, see NEWPROJ.INF Statements.

The default, base-class version of ProcessTemplate uses the dictionary to expand macros.

You can implement new directives by overriding the default behavior of ProcessTemplate to parse them. For information on the standard MFC AppWizard directives, see Standard AppWizard Directives.

See Also CCustomAppWiz Overview, Class Members, Understanding Custom Resource Templates, The Dictionary, Standard AppWizard Directives, Understanding CONFIRM.INF and NEWPROJ.INF, NEWPROJ.INF Statements, CCustomAppWiz::LoadTemplate, CCustomAppWiz::CopyTemplate, CCustomAppWiz::PostProcessTemplate


CCustomAppWiz::m_Dictionary

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

project aw.m_Dictionary[“macroname”] = “value”;

project aw.m_Dictionary.RemoveKey(“macroname”);

Parameters

project

The name of your project as specified on the Projects tab of the New dialog box.

“macroname”

Pointer to the current step. The quotations marks are required.

“value”

Any value that makes sense for your application. The macro exists if it has a value assigned to it. The quotations marks are required.

Remarks

Use the m_Dictionary data member (the dictionary), which is of the type CMapStringToString, to create macros, remove macros, or update the value of macros. Some macros are supplied by MFCAPWZ.DLL and some by you. The CCustomAppWiz::ProcessTemplate member function uses the dictionary to map macros that it encounters while parsing custom resource templates to their actual values. For more information on the macros supplied by MFCAPWZ.DLL, see Standard AppWizard Macros.

Typically, you will call the dictionary’s member functions (which are provided by CMapStringToString) in a custom step’s OnDismiss function.

Each of your custom AppWizard’s custom steps is a dialog box that is represented by a class. Each step’s class has an OnDismiss member function that is called whenever the user of a custom AppWizard chooses Back, Next, or Finish. After you use the dialog resource editor to add controls to your custom steps, use ClassWizard to add variables to each step’s class. In this way, you can take advantage of the dialog data exchange (DDX) code that ClassWizard adds to your class.

Typically, you will add code in each OnDismiss function that defines, provides values for, or removes macros as follows:

BOOL CStep1Dlg::OnDismiss()
{
   if (!UpdateData(TRUE))
      return FALSE;

   else
   {
      if (!m_Indented)
      {
         myaw.m_Dictionary["INDENTED_BRACES"]="";
         myaw.m_Dictionary["NOT_INDENTED_BRACES"]="Yes";
      }
      else
      {
         myaw.m_Dictionary["INDENTED_BRACES"]="\t";
         myaw.m_Dictionary.RemoveKey("NOT_INDENTED_BRACES")=;
      }
      if (m_CompanyLogo)
         myaw.m_Dictionary["COMPANY_LOGO"]="Yes";
      else
         myaw.m_Dictionary.RemoveKey("COMPANY_LOGO");

      if (m_3DControls)
         myaw.m_Dictionary["3-D"]="Yes";
      else
         myaw.m_Dictionary.RemoveKey("3-D");

      return TRUE;   // return FALSE if the dialog
               //  shouldn't be dismissed
   }
}

See Also CCustomAppWiz Overview, Class Members, CAppWizStepDlg::OnDismiss, CustomAppWiz::ProcessTemplate, Standard AppWizard Macros


OutputStream

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The OutputStream class wraps two member functions that are used by CCustomAppWiz::CopyTemplate and CCustomAppWiz::ProcessTemplate when they process custom resource templates. You will only need to call the OutputStream member functions if you override CopyTemplate and/or ProcessTemplate.

See Also Class Members, CCustomAppWiz::CopyTemplate, CustomAppWiz::ProcessTemplate, Understanding Custom Resource Templates


Class Members

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Overridables

WriteLine | Called in CCustomAppWiz::ProcessTemplate to write lines from a custom resource template to an output stream.
WriteBlock | Called in CCustomAppWiz::CopyTemplate to write a custom resource template, usually a bitmap, to an output stream.

See Also OutputStream Overview


OutputStream::WriteBlock

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

WriteBlock( LPCTSTR pBlock, DWORD dwSize );

Parameters

pBlock

Points to a block of memory that usually contains a custom resource template.

dwSize

Size of the block of memory. This must be smaller than or equal to the dwSize returned through the CCustomAppWiz::LoadTemplate argument list.

Remarks

Writes a block of memory to an output stream, usually an open file. The base-class implementation of the CopyTemplate function calls WriteBlock to write a binary template to the output stream specified in the argument list of CopyTemplate.

See Also OutputStream Overview, Class Members, CCustomAppWiz::LoadTemplate, CCustomAppWiz::CopyTemplate, OutputStream::WriteLine, CCustomAppWiz::ProcessTemplate


OutputStream::WriteLine

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

WriteLine( LPCTSTR lpsz );

Parameters

lpsz

Points to a null-termintated string that is a custom resource template.

Remarks

Writes the text pointed to by lpsz, up to and including the first newline character (\n), to an output stream, usually an open file or, in the case of CONFIRM.INF, the display window of the New Project Information dialog box.

CCustomAppWiz::ProcessTemplate parses custom resource templates line by line and calls WriteLine to write each processed line (which can appear as text, source code, or resource script statements) to the output stream specified in the argument list of ProcessTemplate.

See Also OutputStream Overview, Class Members, CCustomAppWiz::LoadTemplate, CCustomAppWiz::ProcessTemplate, CCustomAppWiz::CopyTemplate, OutputStream::WriteBlock


C Functions Exported by MFCAPWZ.DLL

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

These functions, implemented in MFCAPWZ.DLL, provide communication services between your custom AppWizard and MFCAPWZ.DLL.

Exported C Functions

GetDialog | Gets a pointer to the specified standard MFC AppWizard step. This function is called by a custom AppWizard that uses one of the standard sequences of MFC AppWizard steps.
SetCustomAppWizClass | Provides a pointer to your custom AppWizard’s CCustomAppWiz class.
SetNumberOfSteps | Sets the number of steps in your custom AppWizard.
ScanForAvailableLanguages | Scans for all of the localized resource DLLs, those with names described by APPWZ*.DLL, found in the Microsoft Visual Studio\Common\msdev98\bin\ide directory.
SetSupportedLanguages | Sets the languages that a custom AppWizard supports, which may be different from the localized resource DLLs found in the Microsoft Visual Studio\Common\msdev98\bin\ide directory.

See Also GetDialog, SetCustomAppWizClass, CCustomAppWiz, SetNumberOfSteps, ScanForAvailableLanguages, SetSupportedLanguages


GetDialog

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

CAppWizStepDlg* GetDialog( AppWizDlgID nID );

Return Value

A pointer to the standard MFC AppWizard step specified in the nID argument.

Parameters

nID

The enumerated value of a standard AppWizard step. See below for a list of the possible values.

Remarks

CUSTMWZ.AWX generates calls to GetDialog in the CCustomAppWiz::InitCustomAppWiz function of every custom AppWizard that uses one of the two standard sequences of MFC AppWizard steps; one call for each of the standard MFC AppWizard steps that a custom AppWizard needs. The returned pointers are automatically stored by the custom AppWizard and are returned in response to an MFCAPWZ.DLL call to CCustomAppWiz::Next or CCustomAppWiz::Back.

The actual calls to GetDialog and storage of the returned pointers occurs in the constructor of a CUSTMWZ.AWX-generated class named CDialogChooser. The pointers are stored, sequentially, in an order determined by the original order of the standard MFC AppWizard steps. Pointers to any custom steps you specify are automatically added to the end of the sequence of pointers returned by the calls to GetDialog.

You will probably not add your own call to GetDialog or modify the existing calls to GetDialog unless you want to change the default order in which your custom AppWizard presents steps to its users.

The standard MFC AppWizard offers two different sequences of steps to the AppWizard user: AppWizard Executable and AppWizard Dynamic Link Library. Each step in each sequence is represented by an enumerated value, as shown in the following table.

Enumerated Values of Standard AppWizard Steps

Value | Description
APWZDLG_APPTYPE | Step 1, MFC AppWizard (exe) Allows the user to choose a type of application (single document (SDI), multiple documents (MDI), or dialog based) and the languages into which their application’s resource strings will be translated.
APWZDLG_DATABASE | Step 2, MFC AppWizard (exe) Allows the user to specify the type of database support for SDI and MDI applications. Possible choices are None, Header files only, Database view without file support, or Database view with file support.
APWZDLG_DLGAPPOPTIONS | Step 2, MFC AppWizard (exe) Allows the user to choose standard application features for dialog-based applications (About box, Context-sensitive Help, and 3D controls). Also allows the user to choose Automation, ActiveX Controls or Windows Sockets support and to name the application’s dialog box.
APWZDLG_OLE | Step 3, MFC AppWizard (exe) Allows the user to specify the level of compound document support for SDI and MDI applications (None, Container, Mini-server, Full-server, Both container and server, Active document server). Also allows the user to choose support for compound files and automation and ActiveX controls.
APWZDLG_DOCAPPOPTIONS | Step 4, MFC AppWizard (exe) Allows the user to choose standard application features for MDI and SDI applications (Docking toolbar, Initial status bar, Printing and print preview, Context-sensitive Help, and 3D controls). Allows the user to choose MAPI (Messaging API) and Windows Sockets and to specify the number of files remembered in their application’s most recently used list.
APWZDLG_PROJOPTIONS | Step 5, MFC AppWizard (exe) Step 3, (dialog-based programs) Allows the user to choose whether AppWizard generates commented or uncommented MFC code in their project and whether they want their project linked with the static MFC library or the shared MFC DLL. Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.
APWZDLG_CLASSES | Step 6, MFC AppWizard (exe) Step 4, (dialog-based programs) Allows the user to modify the default class and file names that AppWizard will generate.
APWZDLG_DLLPROJOPTIONS | Step 1, MFC AppWizard (dll) Allows the user to choose whether AppWizard generates commented or uncommented MFC code in their project and whether they want their project linked with the static MFC library or the shared MFC DLL. Also allows the user to choose Automation and Windows Sockets support.

See Also C Functions Exported by MFCAPWZ.DLL, CCustomAppWiz::InitCustomAppWiz, CCustomAppWiz::Next, CCustomAppWiz::Back


SetCustomAppWizClass

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

void SetCustomAppWizClass( CCustomAppWiz pAW );

Parameters

pAW

Points to your CCustomAppWiz class.

Remarks

Called in the DLLMain function of your custom AppWizard to provide MFCAPWZ.DLL with a pointer to your custom AppWizard’s CCustomAppWiz class. The communication services between MFCAPWZ.DLL and your custom AppWizard that are provided by the CCustomAppWiz member functions occur through pAW. The code that calls SetCustomAppWizClass is automatically generated when you use the Custom AppWizard project type to generate your custom AppWizard.

See Also C Functions Exported by MFCAPWZ.DLL, CCustomAppWiz


SetNumberOfSteps

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

void SetNumberOfSteps( int nSteps );

Parameters

nSteps

The total number of steps that your custom AppWizard presents to its users. Set nSteps to -1 to communicate to MFCAPWZ.DLL that you want your custom AppWizard’s title bar to display only the current step number (for example, “Step 1” rather than “Step 1 of 6”). Set nSteps to 0 to communicate to MFCAPWZ.DLL that your custom AppWizard has no steps and only wants to use the New Project Workspace or the Insert Project dialog boxes (for example, when your custom AppWizard is based on an existing project, and there are no options for the custom AppWizard user to select.)

Remarks

Your custom AppWizard calls SetNumberOfSteps in CCustomAppWiz::InitCustomAppWiz to communicate the total number of steps to MFCAPWZ.DLL. The resulting information allows MFCAPWZ.DLL to accurately number the steps in your custom AppWizard’s title bar and to correctly activate or gray the Next button.

Although the initial call to SetNumberOfSteps in InitCustomAppWiz is generated for you, you should also call it when an end user’s choice will change the number of steps the user will see.

See Also C Functions Exported by MFCAPWZ.DLL, CCustomAppWiz::InitCustomAppWiz


ScanForAvailableLanguages

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

BOOL ScanForAvailableLanguages( CStringList& rLanguages );

Return Value

TRUE if one or more localized resource DLLs are found in the Microsoft Visual Studio\Common\msdev98\bin\ide directory, otherwise FALSE.

Parameters

rLanguages

Stores strings describing each localized resource DLL, those with names described by APPWZ*.DLL, found in the Microsoft Visual Studio\Common\msdev98\bin\ide directory.

Remarks

The ScanForAvailableLanguages function requests that MFCAPWZ.DLL scan the Microsoft Visual Studio\Common\msdev98\bin\ide directory and store, in rLanguages, a descriptive string for each localized resource DLL found. Each entry in the list takes the following form:

“language-name (APPWZ*.DLL-name);translation-identifier”

For example:

"U.S. English (appwzenu.dll);0x040904e4"

The translation-identifier is identical to the value of the block header of the “StringFileInfo” block in a Version resource. It’s a DWORD represented in hexadecimal format, with a high word representing the language and a low word representing the character set (code page).

If ScanForAvailableLanguages returns FALSE, MFCAPWZ.DLL displays an error message in a message box. Retry and Cancel buttons allow flexible recovery from this error.

Your custom AppWizard will probably never call ScanForAvailableLanguages. CUSTMWZ.AWX does call ScanForAvailableLanguages to determine which languages the MFC AppWizard currently supports. CUSTMWZ.AWX uses the result to fill the language list for step 2.

See Also AppWizard Language Support for Far East Languages, C Functions Exported by MFCAPWZ.DLL, $$SET_DEFAULT_LANG, SetSupportedLanguages, CCustomAppWiz::GetPlatforms, Language Loop Macros


SetSupportedLanguages

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

SetSupportedLanguages( LPCTSTR szSupportedLangs );

Parameters

szSupportedLangs

Stores a string of the form:

“language-name#1 (APPWZ*.DLL-name#1);translation-identifier#1\n

language-name#2 (APPWZ*.DLL-name#2);translation-identifier#2\n...

...language-name#i (APPWZ*.DLL-name#i);translation-identifier#i\n”

The string is a series of substrings, each separated by the newline character (\n). Each substring has the same format as each entry in the CStringList parameter in ScanForAvailableLanguages.

Remarks

The SetSupportedLanguages function reports to MFCAPWZ.DLL the languages that are supported by your custom AppWizard. This function is only used if your custom AppWizard uses the MFC AppWizard Executable standard sequences of AppWizard steps and is called in CCustomAppWiz::InitCustomAppWiz to fill the languages checklist in MFC AppWizard’s Step 1. The code that calls SetSupportedLanguages is automatically generated when you use the Custom AppWizard project type to generate your custom AppWizard

See Also AppWizard Language Support for Far East Languages, C Functions Exported by MFCAPWZ.DLL, $$SET_DEFAULT_LANG, ScanForAvailableLanguages, CCustomAppWiz::GetPlatforms, Language Loop Macros


Standard AppWizard Directives

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

MFC AppWizard directives, such as $$IF and $$ENDIF, are used to generalize custom resource templates so that the content of the templates can be used for multiple project types. Directives in a template guide the MFCAPWZ.DLL API ProcessTemplate function as it processes a template to produce a project file or the content of the New Project Information dialog box. For example, based on the value of a macro, a sequence of $$IF, $$ELIF, $$ELSE, and $$ENDIF directives can force ProcessTemplate to selectively insert lines of C++ code into a header or an implementation file (.H or .CPP, respectively) used by a project generated by your custom AppWizard.

ProcessTemplate recognizes the following directives:

$$IF | $$BEGINLOOP
$$ELIF | $$ENDLOOP
$$ELSE | $$SET_DEFAULT_LANG
$$ENDIF | $$//
$$INCLUDE |

These directives must appear at the beginning of a line with no preceding white space, and, other than any arguments and one optional comment, there can be nothing else on the line.

If you wish the parser to emit “$$” literally (and not to signify that a macro or directive will follow), use “$$$$”. Occurrences of “$$$$” are translated as “$$”.

See Also $$IF, $$ELIF, $$ELSE, $$ENDIF, $$INCLUDE, $$BEGINLOOP, $$ENDLOOP, $$SET_DEFAULT_LANG, $$SET_DEFAULT_LANG, $$//


$$IF, $$ELIF, $$ELSE, and $$ENDIF

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

$$IF(macro-list)

textA

$$ELIF(macro-list)

textB

$$ELSE

textC

$$ENDIF

Parameters

macro-list

One or more macro names. A macro name can be preceded by the logical NOT operator (!). Multiple macro names are separated by the logical OR (||) operator. A macro name can be one of the standard MFC AppWizard macros or one that you create by adding it to the dictionary.

Remarks

The $$IF directive, with the $$ELIF, $$ELSE, and $$ENDIF directives, controls the flow of control that the ProcessTemplate function follows while parsing a custom resource template.

When the parser encounters an $$IF directive, it searches the dictionary for each macro name it finds in macro-list, in sequential order. The parser checks only for a macro name’s existence in the dictionary, not its value. Once a macro name is found in the dictionary, the parser stops checking the other macro names, the $$IF evaluates to TRUE, and textA is parsed. If the parser finds none of the macro names in the dictionary, the $$IF evaluates to FALSE and the parser processes any subsequent $$ELIF directive’s macro-list as it did the $$IF macro-list. If an $$ELIF evaluates to TRUE, textB is parsed. If no $$ELIF directive evaluates to TRUE, the $$ELSE body (textC) is parsed. The $$ENDIF directive marks the end of the $$IF construct, and normal parsing resumes with the next line.

In the $$IF and $$ELIF arguments, any macro name can be preceded by the logical NOT operator (!) to force the parser to check for non-existence in the dictionary. For example, the following code fragment evaluates to true if MACRO1 is not in the dictionary:

$$IF(!MACRO1)

Each $$IF directive in a custom resource template must be matched by a closing $$ENDIF directive. Multiple $$ELIF directives can appear between the $$IF and $$ENDIF directives, but at most one $$ELSE directive is allowed. That $$ELSE directive, if present, must follow all the $$ELIFs (if any) in that $$IF-$$ENDIF block. If a custom resource template contains an $$IF, any following $$ELIF and/or $$ELSE is optional. An ending $$ENDIF is mandatory. $$IF constructs can be nested up to five levels deep.

There is no logical AND (&&) operator. If you wish to have text parsed only when MACRO1 and MACRO2 are defined, you can accomplish this as follows:

   $$IF(MACRO1)
   $$IF(MACRO2)
   text
   $$ENDIF //MACRO2
   $$ENDIF //MACRO1

See Also Standard AppWizard Directives, The Dictionary, CCustomAppWiz::ProcessTemplate, Standard AppWizard Directives, Standard AppWizard Macros


$$INCLUDE

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

$$INCLUDE( template-name-macro );

Parameters

template-name-macro

A macro name with a value that must be the name of a custom resource template. A macro name can be one of the standard MFC AppWizard macros or one that you create by adding it to the dictionary.

Remarks

The parser searches for an $$INCLUDE directive’s template-name-macro in the dictionary. If template-name-macro is in the dictionary, the associated custom resource template is loaded and parsed. Once the associated template is parsed, parsing of the original template resumes.

Note The template associated with template-name-macro must be a text template and must be parsed using ProcessTemplate. The base-class version of ProcessTemplate will not parse binary templates.

If template-name-macro is not in the dictionary, MFCAPWZ.DLL displays an error message and stops the file generation process. If the template associated with filename-macro is not found, again a message is displayed and an exception is thrown.

You can nest $$INCLUDE directives arbitrarily deep. That is, if one template includes a second template via $$INCLUDE, that second template may include a third via $$INCLUDE, and so on. However, templates cannot be recursively included. That is, if template A includes template B, which includes template C, and so on, then template A cannot be included in the include chain. MFCAPWZ.DLL detects recursive includes, prints an error message, and stops the file generation process.

See Also Standard AppWizard Directives, The Dictionary, CCustomAppWiz::ProcessTemplate, Standard AppWizard Directives, Standard AppWizard Macros


$$BEGINLOOP and $$ENDLOOP

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

$$BEGINLOOP( macro-name );

text

$$ENDLOOP;

Parameters

macro-name

A macro name that you have added to the dictionary with a value that must be a numeric string in decimal format (for example, “12”). The macro-name argument must be the name of a macro, not a constant value.

text

One or more lines of text that may include C++ code, resource script statements, macros, directives, or whatever you parsed.

Remarks

Custom resource templates can use a $$BEGINLOOP and $$ENDLOOP construct to force the CCustomAppWiz::ProcessTemplate function’s parser to process text the number of times specified by the value of macro-name.

The parser treats every macro that it encounters between a $$BEGINLOOP and an $$ENDLOOP, including macro-name, in the following manner:

  1. If, for example, the parser encounters a macro named VAR, it looks in the dictionary for a macro named VAR_n, where n is an integer that corresponds to the number of times that the parser has iterated through text. The iterations are numbered 0, 1, ..., n-1, so that the parser looks for macros named VAR_0, VAR_1, and so on.

  2. If the parser does not find VAR_n in the dictionary, it looks just for VAR.

Loops cannot be nested. A second $$BEGINLOOP before the first $$ENDLOOP is illegal.

See Also Standard AppWizard Directives, The Dictionary, CCustomAppWiz::ProcessTemplate, Standard AppWizard Directives, How Macros Get Their Values


$$SET_DEFAULT_LANG

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

$$SET_DEFAULT_LANG( macro-name );

Parameters

macro-name

A macro name you add to the dictionary. The value of macro-name must be a three-letter string that corresponds to a language previously selected by an MFC AppWizard or custom AppWizard user. The following table provides a partial list of possible values for macro-name.

Language Identifiers

Value | Language
DEU | German
ENU | English
ESP | Spanish
FRA | French
ITA | Italian
JPN | Japanese
SVE | Swedish

Remarks

You use the $$SET_DEFAULT_LANG directive to specify a language-identifer for the CCustomAppWiz::LoadTemplate function to use when it searches for a custom resource template to load for use by CCustomAppWiz::CopyTemplate or CCustomAppWiz::ProcessTemplate.

Note Code to perform the following procedure is automatically generated if your custom AppWizard uses the existing set of MFC AppWizard steps for generating an executable file and if you select more than one language from the Custom AppWizard project type’s language list.

If you use the $$SET_DEFAULT_LANG directive in a loop defined by the $$BEGINLOOP and $$ENDLOOP directives, you can use $$BEGINLOOP and $$ENDLOOP to modify macros to write code that finds, extracts, and processes multiple language versions of a language-specific template. For information on how $$BEGINLOOP and $$ENDLOOP modify macros, see $$BEGINLOOP and $$ENDLOOP.

The language identifier, which is the value of macro-name, also specifies the search order that LoadTemplate uses to search for a DLL.

Say that $$SET_DEFAULT_LANG is called with a macro-name that expands to “DEU”. LoadTemplate will go through the following algorithm to locate a template named TEMPLATE.RC:

  1. Try locating TEMPLATE_DEU.RC in the custom AppWizard’s resources.

  2. If not there, try locating TEMPLATE.RC in the custom AppWizard’s resources.

  3. If not there, try locating TEMPLATE.RC in MFCAPWZ.DLL

  4. If not there, try locating TEMPLATE.RC in APPWZDEU.DLL

  5. If not there, try locating TEMPLATE.RC in all the other APPWZ*.DLLs selected by the custom AppWizard user.

  6. If not there, display an error and stop file generation.

Notice that in step 1, LoadTemplate looks for the template under the localized name (TEMPLATE_DEU.RC). If it can’t find a template named TEMPLATE_DEU.RC in the custom AppWizard’s resources, it reverts back to searching for the actual name (TEMPLATE.RC).

Note If AppWizard itself is being run rather than a custom AppWizard, MFCAPWZ.DLL starts the search process at step 3, and thus never tries to locate the template under the localized name.

Example

Imagine that a user of your custom AppWizard generates a project that will generate an application for use by English-, French-, and Japanese-speaking people. To create the user’s project, your custom AppWizard must find the templates containing strings translated into these languages. It must search in DLLs that include, at least, your custom AppWizard’s DLL, MFCAPWZ.DLL, and possibly APPWZENU.DLL, APPWZFRA.DLL, and APPWZJPN.DLL. For simplicity, we will examine finding and loading one template, FILE.TXT.

Because FILE.TXT is a text file, it will probably be translated into English, French, and Japanese. Your custom AppWizard’s DLL must contain three versions of this file named FILE_ENU.TXT, FILE_FRA.TXT, and FILE_JPN.TXT. Also, your custom AppWizard must make the following addition to the dictionary:

myprojectaw.m_Dictionary[“FILE”] = “FILE.TXT”;

To track the three languages specified by the user, you add macros to the dictionary as follows:

myprojectaw.m_Dictionary[“LANG_SUFFIX_0”] = “ENU”;
myprojectaw.m_Dictionary[“LANG_SUFFIX_1”] = “FRA”;
myprojectaw.m_Dictionary[“LANG_SUFFIX_2”] = “JPN”;

Then, when your custom AppWizard must find and load language-specific templates, it does so in a loop as follows:

$$BEGINLOOP(NUM_LANGS)
$$SET_DEFAULT_LANG(LANG_SUFFIX)
$$// Include text from the
$$// properly localized template:
$$INCLUDE(FILE)
$$ENDLOOP

If NUM_LANGS has the value of “3”, then this loop will iterate three times. During each iteration, MFCAPWZ.DLL will modify its lookup procedure for the LANG_SUFFIX macro and CCustomAppwiz::LoadTemplate will modify its template-loading procedure as follows:

  • First iteration: LANG_SUFFIX first becomes LANG_SUFFIX_0. The value of FILE is extracted from the dictionary and, when $$INCLUDE causes LoadTemplate to be called, the value of FILE is combined with the value of LANG_SUFFIX_0 to produce FILE_ENU.TXT.

  • Second iteration: LANG_SUFFIX first becomes LANG_SUFFIX_1. The value of FILE is extracted from the dictionary and, when $$INCLUDE causes LoadTemplate to be called, the value of FILE is combined with the value of LANG_SUFFIX_1 to produce FILE_FRA.TXT.

  • Third iteration: LANG_SUFFIX first becomes LANG_SUFFIX_2. The value of FILE is extracted from the dictionary and, when $$INCLUDE causes LoadTemplate to be called, the value of FILE is combined with the value of LANG_SUFFIX_2 to produce FILE_JPN.TXT.

Thus, the value of LANG_SUFFIX is transformed to “ENU”, “FRA”, and “JPN” and LoadTemplate will know to first load APWZENU.DLL, then APWZFRA.DLL, and finally APWZJPN.DLL if any of the templates it seeks are not in the custom AppWizard’s DLL. For more information on the transformation of macro names, see $$BEGINLOOP and $$ENDLOOP.

Note The argument to the $$SET_DEFAULT_LANG directive must correspond to an APPWZ*.DLL already chosen by the MFC AppWizard or custom AppWizard user. Otherwise, MFCAPWZ.DLL will display an error message and stop file generation immediately after parsing the $$SET_DEFAULT_LANG directive.

See Also AppWizard Language Support for Far East Languages, Standard AppWizard Directives, The Dictionary, CCustomAppwiz::LoadTemplate, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::CopyTemplate, CCustomAppwiz::PostProcessTemplate, $$BEGINLOOP, $$ENDLOOP, Standard MFC AppWizard Directives, How Macros Get Their Values


$$//

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Remarks

The ProcessTemplate function’s parser treats a line beginning with $$// as a comment. A comment can be preceded by just // when it appears after a directive on the same line. The following line is a comment:

$$// This line is a comment

The following line begins with an $$ENDIF directive and ends with a comment:

$$ENDIF //MACRO1

See Also Standard AppWizard Directives, CCustomAppwiz::ProcessTemplate, Standard AppWizard Directives, Standard MFC AppWizard Macros


Standard AppWizard Macros

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This reference describes the macros that the MFC AppWizard uses to generalize its custom resource templates. These macros correspond to, or are related to, controls in the MFC AppWizard steps. You have access to these macros if your custom AppWizard uses one of the standard sequences of MFC AppWizard steps: the MFC AppWizard Executable (exe) or the MFC AppWizard Dynamic-Link Library (dll).

The following macros are organized by the step (for MDI and SDI applications) where they are used. Some of the described macros also appear on analogous steps for dialog-based and DLL applications (for example, 3D is described with the other MDI/SDI step 4 macros, but it is also used by the dialog-based application’s step 2).

The Projects Tab on the New Dialog Box Options

Step 1, Project Type Options

Step 2, Database Options

Step 3, ActiveX Options

Step 4, Application Options

Step 4, Advanced Options, Document Template Strings Tab

Step 4, Advanced Options, Frame Styles Tab

Step 5, Project Options

Step 6, Class and File Names

The following categories also exist:

Miscellaneous Macros

Language Loop Macros


The Projects Tab on the New Dialog Box

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Macro | Type | Description
FULL_DIR_PATH | text | The full path of the directory in which the generated project will be placed (including the new subdirectory), with a trailing backslash.
ROOT | text | The project name, no extension (all uppercase).
Root root | text | The project name, no extension (cases as entered by user).
root_oem | text | The project name, no extension (cases as entered by user), translated to the OEM character set. Affects only upper ASCII characters in the project name (such as an umlauted character).
SAFE_ROOT | text | The project name (all uppercase), entered from the Projects tab of the New dialog box, stripped of any characters that are not alphanumeric characters (a-z, A-Z, and 0-9) or the underscore (_). The resulting value is safe to use in the name of a preprocessor and/or a C/C++ symbol.
Safe_root safe_root | text | The project name (cases as entered by user), entered from the Projects tab of the New dialog box, stripped of any characters that are not alphanumeric characters (a-z, A-Z, and 0-9) or the underscore (_). The resulting value is safe to use in the name of a preprocessor and/or a C/C++ symbol.
TARGET_INTEL | BOOL | The project targets the Intel Win32 operating system.
TARGET_MIPS | BOOL | The project targets the MIPS Win32 operating system.
TARGET_ALPHA | BOOL | The project targets the ALPHA Win32 operating system.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 1, Project Type Options

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Only one of the Project Type macros can be in the dictionary.

Macro | Type | Description
PROJTYPE_MDI | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has selected a multiple document interface.
PROJTYPE_SDI | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has selected a single document interface.
PROJTYPE_DLG | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has selected a dialog-based application.
PROJTYPE_DLL | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the project be a DLL. If this macro is set, the project makefile builds a DLL rather than an executable file.
PROJTYPE_CUSTOMAW | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has selected a Custom AppWizard project type. Note that this macro will rarely be used in a custom AppWizard. It is only used when CUSTMWZ.AWX is launched.
PROJTYPE_GEN | BOOL | Whether the project is a utility project.
PROJTYPE_MAK | BOOL | Whether the project is a makefile project.
PROJTYPE_LIB | BOOL | Whether the project is a static library.
PROJTYPE_CON | BOOL | Whether the project is a console application.
PROJTYPE_OCX | BOOL | Whether the project is a ActiveX control.
NODOCVIEW | BOOL | Whether the MFC application does not need the Document/View architecture.
EXPLAIN_PROJTYPE | text | Description of the wizard that appears in Step 1.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 2, Database Options

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

One or more database macros may be defined.

Macro | Type | Description
DAO | BOOL | Whether the selected data source is DAO; otherwise, it is ODBC.
DB | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has selected, at least, minimal database support. In other words, a radio button other than None is chosen by the user.
DB_CONNECT | text | The default connect string for the data source. This string is returned by a recordset's GetDefaultConnect member function or, by a DAO recordset's GetDefaultDBName member function.
DB_COLSINFO | text | Information on the names of the columns in the recordset. This information is used in the generated .CLW file.
DB_DSN | text | The human-readable name of the data source for this recordset.
DB_NUMCOLS | text | The number of columns in the data source.
DB_SOURCE | text | The default SQL statement returned by the recordset's GetDefaultSQL member function.
DB_VARSINFO | text | A list of the names of the recordset member variables.
OLEDB | BOOL | Whether the datasource selected is a OLE DB source or not.
PARAM_VARS | text | A string containing the declarations of a recordset's parameter member variables. Used in the recordset’s header (.H) file.
PARAM_VAR_BINDINGS | text | A string containing the initialization of a recordset's parameter member variables. Used in the recordset’s constructor, which is in the implementation (.CPP) file for the recordset.
PARAM_RFX | text | A string containing the RFX statements for a recordset’s parameter member variables. Used in the recordset’s DoFieldExchange member function, which is found in the recordset’s .CPP file.
RECSET_VARIABLE | text | The application’s main document class needs to refer to this recordset. This macro expands to the required data member variable of the document class.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 3, ActiveX Options

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Only one of the ActiveX macros can be in the dictionary.

Macro | Type | Description
CONTAINER | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application is only a container.
FULL_SERVER | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application is a full-server.
MINI_SERVER | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application is a mini-server.
CONTAINER_SERVER | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application is a container-server.
ACTIVE_DOC_SERVER | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application is an Active document server.

More than one of the following macros may be set.

Macro | Type | Description
APP_CLSID | text | Struct form of the application's globally unique identifier (GUID). Only used if the user has selected ActiveX support.
APP_CLSID_REG | text | Registration form of the application's GUID. Only used if the user has selected ActiveX support.
APP_CLSID_MACRO | text | Macro form of the application’s GUID. Only used if the user has selected Automation support for a dialog-based application.
AUTOMATION | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has selected Automation support.
COMPFILE | BOOL | Whether the AppWizard user has selected compound file support.
DISPIID_CLSID_ODL | text | ODL form of the dispinterface GUID. Only used if the user has selected Automation support.
LIB_CLSID_ODL | text | ODL form of the library's GUID. Only used if the user has selected Automation support.
OLECTL | BOOL | Whether the application supports using ActiveX Controls.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 4, Application Options

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The following options are set from the Step 4 Application Options dialog box.

Macro | Type | Description
APPWIZ_INITIAL_DLG | text | The dialog resource to open after the wizard ends.
TOOLBAR | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application have a toolbar.
STATUSBAR | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application have a status bar.
PRINT | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application have printing support.
HELP | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application have context-sensitive help.
3D | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application use 3D controls.
ABOUT | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the dialog-based application include an About box.
MAPI | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the application include MAPI support.
SOCKETS | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified that the project have Windows Sockets support.
HAS_MRU | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified a nonzero value in the most recently used (MRU) text box.
REBAR | BOOL | Whether the project has IE Rebars.
SIZE_MRU | text | The value in the MRU text box.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 4, Advanced Options, Document Template Strings Tab

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The following macros are set from the Document Template Strings tab of the Step 4 Advanced Options dialog box.

Macro | Type | Description
DOC | text | The value in the Doc type name text box.
DOC_FILENEW | text | The document's File New string.
DOC_FILTER | text | The document's (Win32) filter string.
DOC_REGID | text | The value entered in the File Type Name text box.
DOC_REGNAME | text | The document's registration database name.
HAS_SUFFIX | BOOL | Whether the application has a document suffix (extension) specified.
TITLE | text | The caption string for an application’s main title bar or, in a dialog-based application, the dialog’s title.
SUFFIX | text | If HAS_SUFFIX is defined, SUFFIX is the user-specified document suffix for the application.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 4, Advanced Options, Window Styles Tab

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The following macros are set from the Window Styles tab of the Step 4 Advanced Options dialog box.

Macro | Type | Description
FRAME_STYLES | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified nondefault main frame styles.
SW_ARG | text | Argument to the ShowWindow function. Normally this is “m_nCmdShow”, but if the user has chosen “maximized” or “minimized” for the main frame, this value is “SW_SHOWMAXIMIZED” or “SW_SHOWMINIMIZED”, respectively.
FRAME_STYLE_FLAGS | text | If nondefault main frame styles are selected by the AppWizard user, this macro’s value represents the selected main frame styles and is added to the style data member of the CREATESTRUCT passed to PreCreateWindow.
MDICHILD | BOOL | Whether the standard MFC AppWizard user or custom AppWizard user has specified splitter windows in an MDI application and/or chosen nondefault child frame styles. AppWizard must generate a class derived from CMDIChildWnd.
CHILD_FRAME_STYLES | BOOL | TRUE, if the user has chosen nondefault child frame styles.
CHILD_FRAME_STYLE_FLAGS | text | If nondefault child frame styles are selected by the AppWizard user, the value of this macro is the text that represents the selected child frame styles, and is added to the style data member of the CREATESTRUCT passed to PreCreateWindow.
SPLITTER_MDI | BOOL | TRUE, if the AppWizard user has chosen splitter windows in an MDI application.
SPLITTER_SDI | BOOL | TRUE, if the AppWizard user has chosen splitter windows in an SDI application.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 5, Project Options

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Macro | Type | Description
VERBOSE | BOOL | TRUE, if the user chooses to include source comments and README.TXT.
MFCDLL | BOOL | TRUE, if the project uses MFC in a DLL.
PROJTYPE_EXPLORER | BOOL | TRUE, if the project is a Windows Explorer-style application.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Step 6, Class and File Names

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The MFC AppWizard creates macros to name classes and files by combining the prefixes listed in the table “Macro Prefixes” with any of the components listed in the table “Macro Components.” For example, the value of a combined macro DOC_CLASS will be the name of the application’s document class, typically, something like “CProjectDoc.” No single application will use all combinations.

Macro Prefixes

Macro Prefix | Description
DOC | Refers to the application’s document class.
APP | Refers to the application’s CWinApp-derived class.
FRAME | Refers to the application’s main frame class (derived from CFrameWnd or CMDIFrameWnd).
CHILD_FRAME | Refers to the application’s MDI child frame class (CMDIChildFrameWnd).
VIEW | Refers to the application’s view class.
DLG | Refers to the application’s main dialog class. Only used for a dialog-based application.
DLGAUTOPROXY | Refers to the application’s Automation proxy class for the main dialog. Only used for dialog-based applications with Automation.
RECSET | Refers to the application’s main recordset class.
SRVRITEM | Refers to the application’s main server-item class (derived from CServerItem).
CNTRITEM | Refers to the application’s main container-item class (derived from CContainerItem).
IPFRAME | Refers to the application’s in-place frame class (derived from CIPFrameWnd).
TREEVIEW_CLASS | The class name of the treeview for the Windows Explorer-style application.
TREEVIEW_BASE_CLASS | The base class name of the treeview for the Windows Explorer-style application.
TREEVIEW_IFILE | The class's implementation file name (minus extension) of the treeview for the Windows Explorer-style application.
TREEVIEW_HFILE | The class's header file name (minus extension) of the treeview for the Windows Explorer-style application.
WNDVIEW_CLASS | The class name of the view for the NODOCVIEW MFC application.
WNDVIEW_BASE_CLASS | The base class name of the view for the NODOCVIEW MFC application.
WNDVIEW_IFILE | The class's implementation file name (minus extension) of the view for the NODOCVIEW MFC application.
WNDVIEW_HFILE | The class's header file name (minus extension) of the view for the NODOCVIEW MFC application.

Macro Components

Macro Component | Description
_CLASS | Class name.
_BASE_CLASS | Base class name.
_IFILE | Class implementation filename (without the extension). Both uppercase and lowercase versions of these macros are defined. If the macro name is uppercase (for example, APP_IFILE), its value will be uppercase (for example, PROJECT). If the macro name is lowercase (for example, app_ifile), its value will be lowercase (for example, project).
_HFILE | Class header filename (without the extension). Both uppercase and lowercase versions of these macros are defined. If the macro name is uppercase (for example, APP_HFILE), its value will be uppercase (for example, PROJECT). If the macro name is lowercase (for example, app_hfile), its value will be lowercase (for example, project).

Only one of the following macros is defined to indicate the main view's base class.

Macro | Type | Description
CDaoRecordView | BOOL | If and only if the view derives from CdaoRecordView. Set if the user has selected a DAO database view with or without file support.
CListView | BOOL | If and only if the view derives from CListView.
CTreeView | BOOL | If and only if the view derives from CTreeView.
CRichEditView | BOOL | If and only if the view derives from CRichEditView.
CView | BOOL | If and only if the view derives from CView..
CFormView | BOOL | If and only if the view derives from CFormView.
CScrollView | BOOL | If and only if the view derives from CScrollView.
CEditView | BOOL | If and only if the view derives from CEditView.
CRecordView | BOOL | If and only if the view derives from CRecordView. Set if user has selected an ODBC database view with or without file support.
CHtmlView | BOOL | If and only if the view class is derived from CHtmlView.

See Also Standard AppWizard Macros, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Miscellaneous Macros

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Macro | Type | Description
DLGLOC_RC | text | This is always "DLGLOC.RC", and is used in an $$INCLUDE directive in the DLGALL.RC custom resource template.
HM_FILE | text | Used to make the .HLP file. Base name of the .HM file.
HM_FILE_OEM | text | Used to make the .HLP file. Base name of the .HM file translated to the OEM character set. Affects only upper ASCII characters in the project name (such as an umlauted character).
FILE_NAME_SYMBOL | text | Macros used at the top of header file templates to avoid multiple inclusions of the generated header file. For example, may of the headers have code such as #if !defined($$FILE_NAME_SYMBOL$$_INCLUDED_) #define $$FILE_NAME_SYMBOL$$_INCLUDED_ main template code goes here… #endif // !defined($$FILE_NAME_SYMBOL$$_INCLUDED)
LANG_LIST_SUFFIXES | text | Comma-separated string containing a list of the three-letter abbreviations of all languages selected by the AppWizard user (for example, "ENU, FRA"). If an application supports only one language, the list is "".
LICENSED | BOOL | Adds a licensing step to a .lic file in an OCX.
LOC_RC | text | This is always "LOC.RC", and is used in an $$INCLUDE directive in the ALL.RC custom resource template.
MFCPath | text | Path on the AppWizard user’s computer where the MFC library resides.
YEAR | text | The current year (4 digits).

See Also The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Language Loop Macros

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The following macros are used in a language loop, which is a block of text delimited by the $$BEGINLOOP(NUM_LANGS) and $$ENDLOOP directives.

Macro | Type | Description
LANGUAGE | text | Name of language (for example, "U.S. English").
LANG_SUFFIX | text | Three-letter abbreviation of language (for example, "ENU").
HLP_DIR_LOC | text | Name of directory to be created in the generated project, which will contain the localized elements of the application's context-sensitive help (for example, "HLP\ENU"; in an application with only one language, this is always "HLP").
RES_DIR_LOC | text | Name of directory to be created in the generated project, which will contain those files included by the application's .RC file that are localized (for example, "RES\ENU"; in an application with only one language, this is always "RES").
RES_DIR_LOC_DBLSLASH | text | Same as RES_DIR_LOC, except any backslashes are doubled (for example, "RES\\ENU"; again, this is always "RES" in an application with only one language).
MFC_DIR_LOC | text | Name of directory that contains the localizable resources the application will include from MFC. All backslashes are doubled. (For example, "L.FRA\\"; all English resources from MFC are in the main include directory. This macro expands to "" in the case of English.)
LANG_PREAMBLE text Code that is inserted in the application's .RC file, which precedes a localized resource.

For example:

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE 9, 1
#pragma code_page(1252)
#endif

(In an application with only one language, this is "".)
LANG_PREAMBLE_INQUOTES text Same as LANG_PREAMBLE, except each line is tabbed and enclosed in quotes:

For example:

"#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)"
   "#ifdef _WIN32"
   "LANGUAGE 9, 1"
   "#pragma code_page(1252)"
   "#endif"
LANG_POSTAMBLE text Code that's inserted in the application's .RC file, which follows a localized resource.

For example:

#endif

(In an application with only one language, this is "".)
LANG_POSTAMBLE_INQUOTES text Same as LANG_POSTAMBLE, except each line is tabbed and enclosed in quotes:

For example:

   "#endif"

(In an application with only one language, this is "".)
NUM_LANGS | text | The number of languages the user has chosen. (Commonly used as the argument to $$BEGINLOOP.)
MULTIPLE_LANGS | BOOL | Whether the user chose more than one language. Currently, never defined. Reserved for future use.
USE_DEFAULT_LANGUAGE | text | If you set this dictionary value to be non-blank, the default language will be automatically chosen for you as the only choice when working with the Language Loop macros. If you do not set this macro and do not call SetSupportedLanguages, iterating over the language loops will give you entries for each language you have an apwz*.dll for on your system.

See Also AppWizard Language Support for Far East Languages, The Dictionary, CCustomAppwiz::ProcessTemplate, CCustomAppwiz::PostProcessTemplate, How Macros Get Their Values


Standard Custom Resource Templates

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The MFC AppWizard uses a standard set of custom resource templates to build the projects it generates. It also copies some subset of these templates to custom AppWizard projects that are based on the standard MFC AppWizard steps. These templates allow custom AppWizards to generate projects just as the standard MFC AppWizard does.

These standard templates provide a common look and feel to applications created from AppWizard projects and include templates from which .H, .CPP, .RC, .CLW, .ODL, and .RC2 files are built. They also include bitmaps of standard user-interface components and templates that simplify generating help files.

Localization of Standard Templates

The standard templates are separated into two main categories: localized and nonlocalized. Localized templates contain strings that have been translated into languages other than English. These strings are stored in the language DLLs, DLLs with names described by APPWZ*.DLL, where * is a language code such as ENU or JPN. The nonlocalized templates are stored in MFCAPWZ.DLL. When a localized template is generated for a custom AppWizard project, the template’s filename will contain an embedded language code. Thus, for a custom AppWizard that supports Japanese, the templates named DLGLOC.RC and ROOT.HPJ will be renamed as DLGLOC_JPN.RC and ROOT_JPN.HPJ. The names of nonlocalized templates remain the same.

AppWizard provides a set of templates that are common to all project types and some that are unique to each major project type. Major project types are dynamic-link library, dialog-based, single document interface (SDI), and multiple document interface (MDI). In addition, AppWizard provides resource templates for help files, as well as database, and ActiveX applications. The following sections provide details about the individual templates:

All AppWizard Projects

Dialog-Based Applications

Dynamic-Link Libraries

MDI and SDI Applications

ActiveX Applications

Help File Support

Custom AppWizard Help File Support

Database Applications


All AppWizard Projects

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The standard MFC AppWizard copies the following resource templates into every AppWizard project:

README.TXT

Two of these templates are generated: one in a custom AppWizard project’s root directory and one in the custom AppWizard project’s TEMPLATE directory. The first describes the files that the standard MFC AppWizard generated for your custom AppWizard project. The second is a template that the custom AppWizard writer uses to create a README.TXT file for the custom AppWizard user. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.RC2

This secondary resource script file is copied to your custom AppWizard project’s TEMPLATE directory. Its purpose is to contain those resources that are not edited in the development environment. Resources that are edited in the development environment are kept in the main .RC file. This file is one of the templates provided by MFCAPWZ.DLL.

STDAFX.CPP

This implementation file is copied to your custom AppWizard project’s TEMPLATE directory. It is used to build a precompiled header (.PCH) file and a precompiled types file named STDAFX.OBJ. This file is one of the templates provided by MFCAPWZ.DLL.

STDAFX.H

This header file is copied to your custom AppWizard project’s TEMPLATE directory. It is used to build a .PCH file and a precompiled types file named STDAFX.OBJ. This file is one of the templates provided by MFCAPWZ.DLL. It is important that you neither define nor undefine any of the _AFX_NO_XXX macros in stdafx.h. See the Knowledge Base article "PRB: Problems Occur When Defining _AFX_NO_XXX". You can find Knowledge Base articles on the MSDN Library CD, or at http://www.microsoft.com/kb/.

See Also Standard Custom Resource Templates, Dialog-Based Applications, Dynamic-Link Libraries, MDI and SDI Applications, ActiveX Applications, Help File Support, Custom AppWizard Help File Support, Database Applications.


Dialog-Based Applications

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

DIALOG.CPP

The primary implementation file for the project’s main dialog box and About dialog box. This file is one of the templates provided by MFCAPWZ.DLL.

DLGPROXY.CPP

The implementation file for the project’s Automation proxy class for the main dialog. This is only used if you have chosen Automation support. This file is one of the templates provided by MFCAPWZ.DLL.

DIALOG.H

The primary header file for the project’s main dialog box and About dialog box. This file is one of the templates provided by MFCAPWZ.DLL.

DLGPROXY.H

The header file for the project’s Automation proxy class for the main dialog. This is only used if you have chosen Automation support. This file is one of the templates provided by MFCAPWZ.DLL.

DLGALL.RC

The primary resource script file that contains all resources that are not localized (translated into languages such as French or Japanese). DLGALL.RC includes (via $$INCLUDE directives) a resource script file, DLGLOC.RC, that contains all of the localized templates. DLGALL.RC is one of the templates provided by MFCAPWZ.DLL.

DLGLOC.RC

The localized resource script file. A localized version of this template resides in each of the localized-resource DLLs, those with names described by APPWZ*.DLL, such as APPWZDEU.DLL. This template is also used for DLL projects.

DLGRES.H

The primary header file for resources. This template is also used for dynamic-link libraries. This file is one of the templates provided by MFCAPWZ.DLL.

DLGROOT.CLW

ClassWizard information file for dialog-based applications generated by AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

DLGROOT.CPP

The primary implementation file, project.CPP, where project is the project name entered by the end user of the custom AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

DLGROOT.H

The primary header file, project.H, where project is the project name entered by the end user of the custom AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.ICO

The application icon. This template is also used by MDI and SDI applications. It is one of the templates provided by MFCAPWZ.DLL.

See Also Standard Custom Resource Templates, All AppWizard Projects, Dynamic-Link Libraries, MDI and SDI Applications, ActiveX Applications, Help File Support, Custom AppWizard Help File Support, Database Applications.


Dynamic-Link Libraries

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

DLGRES.H

The primary header file for resources. This template is also used for dialog-based applications. It is one of the templates provided by MFCAPWZ.DLL.

DLLROOT.CLW

The ClassWizard information file for DLLs generated by the MFC AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

DLLROOT.CPP

The primary implementation file, project.CPP, where project is the project name entered by the end user of the custom AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

DLLROOT.H

The primary header file, project.H, where project is the project name entered by the end user of the custom AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.DEF

The module-definition file, project.H, where project is the project name entered by the end user of the custom AppWizard. The module-definition file contains the list of functions to be exported from the end user’s DLL. This file is one of the templates provided by MFCAPWZ.DLL.

See Also Standard Custom Resource Templates, All AppWizard Projects, Dialog-Based Applications, MDI and SDI Applications, ActiveX Applications, Help File Support, Custom AppWizard Help File Support, Database Applications.


MDI and SDI Applications

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

AFXcore.RTF

A rich-text file for generating a help (.HLP) file. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

ALL.RC

The primary resource script file that resides in MFCAPWZ.DLL and contains all resources that are not localized (translated into languages such as French or Japanese). ALL.RC includes, via $$INCLUDE directives, two localized templates that contain all of the localized resources: LOC.RC and MACLOC.RC. Localized versions of these templates reside in each of the localized-resource DLLs, those with names described by APPWZ*.DLL, such as APPWZDEU.DLL.

CHILDFRM.CPP

The child-frame implementation file. This file is one of the templates provided by MFCAPWZ.DLL.

CHILDFRM.H

The child-frame header file. This file is one of the templates provided by MFCAPWZ.DLL.

DOC.CPP

The document implementation file. This file is one of the templates provided by MFCAPWZ.DLL.

DOC.H

The document header file. This file is one of the templates provided by MFCAPWZ.DLL.

DOC.ICO

The document icon. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

FRAME.CPP

The main-frame implementation file. This file is one of the templates provided by MFCAPWZ.DLL.

FRAME.H

The main-frame header file. This file is one of the templates provided by MFCAPWZ.DLL.

LOC.RC

The localized resource script file that contains all the localizable lines of the .RC file. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

RESOURCE.H

The primary header file for resources. It is one of the templates provided by MFCAPWZ.DLL.

ROOT.CPP

The primary implementation file, project.CPP, where project is the project name entered by the end user of the custom AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.H

The primary header file, project.H, where project is the project name entered by the end user of the custom AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.CLW

The ClassWizard information file for SDI and MDI applications generated by AppWizard. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.ICO

The application icon. This template is also used by dialog-based applications. It is one of the templates provided by MFCAPWZ.DLL.

VIEW.CPP

The view implementation file. This file is one of the templates provided by MFCAPWZ.DLL.

VIEW.H

The view header file. This file is one of the templates provided by MFCAPWZ.DLL.

APPEXIT.BMP

A bitmap, for use in help files, that creates the user interface for closing the application. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

BULLET.BMP

A bitmap, for use in help files, that creates a bullet for items in a bulleted list. This file is one of the resource templates provided by MFCAPWZ.DLL.

CURARW2.BMP

A bitmap, for use in help files, that creates the horizontal-sizing cursor. This file is one of the resource templates provided by MFCAPWZ.DLL.

CURARW4.BMP

A bitmap, for use in help files, that creates the move cursor. This file is one of the resource templates provided by MFCAPWZ.DLL.

CURHELP.BMP

A bitmap, for use in help files, that creates the toolbar button for SHIFT+F1 help. This file is one of the resource templates provided by MFCAPWZ.DLL.

EDITCOPY.BMP

A bitmap, for use in help files, that creates the toolbar button for the Edit menu’s Copy command. This file is one of the resource templates provided by MFCAPWZ.DLL.

EDITCUT.BMP

A bitmap, for use in help files, that creates the toolbar button for the Edit menu’s Cut command. This file is one of the resource templates provided by MFCAPWZ.DLL.

EDITPAST.BMP

A bitmap, for use in help files, that creates the toolbar button for the Edit menu’s Paste command. This file is one of the resource templates provided by MFCAPWZ.DLL.

EDITUNDO.BMP

A bitmap, for use in help files, that creates the toolbar button for the Edit menu’s Undo command. This file is one of the resource templates provided by MFCAPWZ.DLL.

FILENEW.BMP

A bitmap, for use in help files, that creates the toolbar button for the File menu’s New command. This file is one of the resource templates provided by MFCAPWZ.DLL.

FILEOPEN.BMP

A bitmap, for use in help files, that creates the toolbar button for the File menu’s Open command. This file is one of the resource templates provided by MFCAPWZ.DLL.

FILEPRNT.BMP

A bitmap, for use in help files, that creates the toolbar button for the File menu’s Print command. This file is one of the resource templates provided by MFCAPWZ.DLL.

FILESAVE.BMP

A bitmap, for use in help files, that creates the toolbar button for the File menu’s Save command. This file is one of the resource templates provided by MFCAPWZ.DLL.

HLPSBAR.BMP

A bitmap, for use in help files, that creates the status bar. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

HLPTBAR.BMP

A bitmap, for use in help files, that creates a cutaway view of the toolbar. This file is one of the resource templates provided by MFCAPWZ.DLL.

RECFIRST.BMP

A bitmap, for use in help files, that creates the toolbar button for the Record menu’s First command. This file is one of the resource templates provided by MFCAPWZ.DLL.

RECLAST.BMP

A bitmap, for use in help files, that creates the toolbar button for the Record menu’s Last command. This file is one of the resource templates provided by MFCAPWZ.DLL.

RECNEXT.BMP

A bitmap, for use in help files, that creates the toolbar button for the Record menu’s Next command. This file is one of the resource templates provided by MFCAPWZ.DLL.

RECPREV.BMP

A bitmap, for use in help files, that creates the toolbar button for the Record menu’s Previous command. This file is one of the resource templates provided by MFCAPWZ.DLL.

SCMAX.BMP

A bitmap, for use in help files, that creates the frame’s maximize button. This file is one of the resource templates provided by MFCAPWZ.DLL.

SCMENU.BMP

A bitmap, for use in help files, that creates a cutaway view of the System and File menus. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

SCMIN.BMP

A bitmap, for use in help files, that creates the frame’s minimize button. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBA___.BMP

A bitmap that creates the default toolbar. The toolbar does not include a Help button. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBAH__.BMP

A bitmap that creates the default toolbar and includes a Help button. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBD__.BMP

A bitmap that creates the default toolbar and includes a database view without file support. The toolbar does not include a Help button. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBDH_.BMP

A bitmap that creates the default toolbar and includes a database view with no file support. The toolbar includes a Help button. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBR__.BMP

A bitmap that creates the default toolbar and includes a database view and file support. The toolbar does not include Help button. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBRH_.BMP

A bitmap that creates the default toolbar and includes a database view and file support. The toolbar includes a Help button. This file is one of the resource templates provided by MFCAPWZ.DLL.

See Also Standard Custom Resource Templates, Dialog-Based Applications, Dynamic-Link Libraries, ActiveX Applications, Help File Support, Custom AppWizard Help File Support, Database Applications.


ActiveX Applications

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

AFXOLECL.RTF

A rich-text file for generating a help (.HLP) file containing information on MDI and SDI containers. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

AFXOLESV.RTF

A rich-text file for generating an MDI and SDI server application’s help file. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

CNTRITEM.CPP

The container-item implementation file for MDI and SDI container applications.

CNTRITEM.H

The container-item header file for MDI and SDI container applications.

IPFRAME.CPP

The in-place frame implementation file for MDI and SDI server applications.

IPFRAME.H

The in-place frame header file for MDI and SDI server applications.

ROOT.REG

The registry information file to contain the globally unique identifier (GUID) that an application must expose to the registry, along with all other information needed to register the generated application as a server or the default editor of a particular document type. All references to a GUID in this file are through AppWizard macros whose values are set when the end user chooses Active Document Server or Automation from the ActiveX Options dialog box.

ROOT.ODL

The Object Description Language file to contain a GUID for each object that an application must expose through Automation. All references to a GUID in this file are through AppWizard macros whose values are set when the end user chooses Automation from the ActiveX Options dialog box.

SRVRITEM.CPP

The server-item implementation file for MDI and SDI server applications.

SRVRITEM.H

The server-item header file for MDI and SDI server applications.

TBA_I.BMP

A bitmap file that creates an in-place frame toolbar for default server and mini-server applications. The toolbar does not include a Help button. A server application displays TBA_I.BMP, rather than TBA__.BMP, upon activation as an in-place server from within a container application. Mini-servers only use the in-place toolbar because mini-servers can’t be launched as stand-alone applications. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBAHI.BMP

A bitmap file that creates an in-place frame toolbar for default server and mini-server applications. The toolbar includes a Help button. A server application displays TBAHI.BMP, rather than TBAH_.BMP, upon activation as an in-place server from within a container application. Mini-servers only use the in-place toolbar because mini-servers can’t be launched as stand-alone applications. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBRHI.BMP

A bitmap file that creates a floating, dockable toolbar for the in-place frame toolbar, which includes database view and file support. The toolbar includes a Help button. A server application with a database view displays TBRHI.BMP, rather than TBRH_.BMP, upon activation as an in-place server from within a container application. Mini-servers only use the in-place toolbar because mini-servers can’t be launched as stand-alone applications. This file is one of the resource templates provided by MFCAPWZ.DLL.

TBR_I.BMP

A bitmap file that creates a floating, dockable toolbar for the in-place frame toolbar, which includes database view and file support. The toolbar does not include a Help button. A server application with a database view displays TBR_I.BMP, rather than TBR__.BMP, upon activation as an in-place server from within a container application. Mini-servers only use the in-place toolbar because mini-servers can’t be launched as stand-alone applications. This file is one of the resource templates provided by MFCAPWZ.DLL.

See Also Standard Custom Resource Templates, All AppWizard Projects, Dialog-Based Applications, Dynamic-Link Libraries, MDI and SDI Applications, Help File Support, Custom AppWizard Help File Support, Database Applications.


Help File Support

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

AFXDLG.RTF

This rich-text file is copied to your custom AppWizard project’s TEMPLATE directory. It is used to generate a help (.HLP) file for dialog-based applications. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

AFXPRINT.RTF

This rich-text file is copied to your custom AppWizard project’s TEMPLATE directory. It contains only print and print preview topics and is used to generate a help file for MDI and SDI applications that use printing and print preview. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

DLGROOT.CNT

Windows 95 WinHelp contents file for dialog-based applications. This text file creates the hierarchy of help topics that is displayed on the Contents tab of your custom AppWizard’s help file. The nodes of the hierarchy are links into the actual help file. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.CNT

Windows 95 WinHelp contents file for SDI and MDI applications. This text file creates the hierarchy of help topics that is displayed on the Contents tab of your custom AppWizard’s help file. The nodes of the hierarchy are links into the actual help file. This file is one of the templates provided by MFCAPWZ.DLL.

ROOT.HPJ

This help project file is copied to your custom AppWizard project’s TEMPLATE directory. It is used to generate Win32 application help files and lists all of the .RTF files that the Help Workshop (HCW.EXE) must process to produce an .HLP file. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

See Also Standard Custom Resource Templates, AppWizard Language Support for Far East Languages, All AppWizard Projects, Dialog-Based Applications, Dynamic-Link Libraries, MDI and SDI Applications, ActiveX Applications, Custom AppWizard Help File Support, Database Applications.


Custom AppWizard Help File Support

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The MFC AppWizard gives you the tools you need to create context-sensitive help for the custom steps in your custom AppWizard:

  • A starter file in rich-text format (.RTF) that contains a topic for each custom step AppWizard generates. You need only use an .RTF editor (such as Microsoft Word) to supply the text for the ready-made topics.

  • Custom build rules on the .hpj, .cnt and resource.hlp file that generate a header map (.HM) file and compiles the custom AppWizard’s help (.HLP) file. The .HM file defines (#define) the help IDs of your custom custom AppWizard steps to numeric values that are readable by the help compiler (HCRTF.EXE). It also invokes the help compiler to generate the help file.

    A MakeHelp.bat is also supplied for projects in Visual C++ 6.0 for compatibility with previous releases.

  • A help project (.HPJ) file that controls compiling the .RTF file into an .HLP file.

Your custom AppWizard file, which has an extension of .AWX, and its help file must use the same base filename, and both must reside in Microsoft Visual Studio\Common\msdev98\Template. When the custom AppWizard user clicks a custom step’s Help button, MFCAPWZ.DLL invokes WinHelp and passes it the current step’s help ID and the name of your custom AppWizard’s help file.

Note You cannot integrate your custom AppWizard’s help with the Visual C++ help system. However, if you build a custom AppWizard that uses an existing sequence of AppWizard steps, your custom AppWizard will automatically use the Visual C++ help file that was created for the standard MFC AppWizard steps. Your custom AppWizard will use your own WinHelp help file for the custom steps. The effect is seamless to the user.

See Also Standard Custom Resource Templates, All AppWizard Projects, Dialog-Based Applications, Dynamic-Link Libraries, MDI and SDI Applications, ActiveX Applications, Help File Support, Database Applications.


Database Applications

Home | Overviews | How Do I | Details | Sample

Feature Only in Professional and Enterprise Editions Creating a Custom AppWizard is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The following resources support the database features that the MFC AppWizard offers. Custom AppWizards cannot support database projects but they can be used to provide database support in MFC projects.

AFXDB.RTF

Rich text file. for generating a database-application help (.HLP) file. This file is one of the resource templates provided by the localized language DLLs, such as APPWZJPN.DLL.

RECSET.CPP

Recordset implementation file for MDI and SDI applications. This file is one of the templates provided by MFCAPWZ.DLL.

RECSET.H

Recordset header file for MDI and SDI applications. This file is one of the templates provided by MFCAPWZ.DLL.

TBDH_.BMP

Bitmap file that creates a toolbar for database view applications without file support. This file is one of the resource templates provided by MFCAPWZ.DLL.

See Also Standard Custom Resource Templates, All AppWizard Projects, AppWizard Language Support for Far East Languages, Dialog-Based Applications, Dynamic-Link Libraries, MDI and SDI Applications, ActiveX Applications, Help File Support, Custom AppWizard Help File Support.


Compiling and Linking

This section covers the compiler, linker, and other tools related to building. You can build your program from within the development environment or from the command line.
Overviews
How Do I
Frequently Asked Questions
Details
What else do you want to do?
See a reference list of compiler options.
Set compiler options.
See a reference list of linker options.
Set linker options.
Set environment variables.

Interesting home pages
Visual C++ Home The entire Visual C++ product.
Debugging Debugging your program.
Build error messages Reference information on error messages generated by the build tools.


Overviews: Compiling and Linking

Home | How Do I | Details

The first step in the process of building a program is creating source code files with the code statements in header and/or source files. When you invoke the compiler, the preprocessor runs first to create the compiler input. The compiler creates an object file that contains machine code, linker directives, sections, external references, and function and data names generated from the source files. Finally, the linker combines all of the object code from statically-linked libraries and other object files, resolves the named resources, and creates an executable file. Typically, a makefile coordinates the combination of these elements and tools in creating the executable file.

  • Building from Within the Development Environment

  • Building on the Command Line

  • Building Projects Not Created in the Development Environment (or “External” Projects)

  • Optimizing Your Code

  • Creating a Release Build

  • Additional Command-Line Build Tools

The build process


Building from Within the Development Environment: Overview

Home | How Do I | Details

If you have an existing makefile that you want to use in Visual C++ 6.0, see:

  • Upgrade Previous 32-Bit Versions of Visual C++

  • Port Applications to and from the development environment

See Working with Projects for a general overview of managing projects. Also see Upgrade Previous 32-Bit Versions of Visual C++ if necessary for porting your existing projects.

In the Project Settings dialog box (Project menu), you can quickly set build options for any configuration in a project, any file in a configuration, or all the files in a project. If you have file types in your project that the build system does not process by default, you can specify custom commands to process those files.

Once you have specified the projects in your workspace, the configurations that your project is to build, and the tool settings for those configurations, you can build the project with the commands on the Build menu. If you are creating an application for a platform other than the one on which you are running Visual C++, the development environment can automatically transfer the application to the remote machine after it is built.

See Also Building on the Command Line


Building on the Command Line: Overview

Home | How Do I | Details

To build your program outside the development environment, specify build options at the command prompt or in a makefile. Click below for a list of compiler or linker options, or for reference guides on the primary tools for building your program outside of the development environment.

  • Building Projects Not Created in the Development Environment

  • Compiler options and reference

  • Linker options and reference

  • NMAKE reference guide

  • Environment Variables and VCVARS32

  • Additional command-line build tools


Building Projects Not Created in the Development Environment

Home | How Do I | Details

A project not created in the Visual C++ development environment is considered an “external” project because it originally used methods outside of (or external to) the current Visual C++ development environment to set compiler or linker options, for instance, rather than using the methods available within the development environment. Sometimes a makefile is an external project, as far as Visual C++ is concerned.

In Microsoft Visual C++ there are two types of “external” projects:

  • Projects that are built using a makefile not created by the current version of the development environment.

    You can open an existing makefile in the development environment to create an external project. The development environment uses NMAKE to build the external project, and automatically sets certain internal project options to build the project with NMAKE. You can continue to use external methods to set options, if you choose.

  • Projects that are built using methods other than the internal build system in the development environment.

    You can specify a new project with the Makefile project type, and then specify tools other than NMAKE which the development environment needs to run to build the project, using the Project Settings dialog box.

All external projects use project settings on the General tab of the Project Settings dialog box. If you open an existing makefile, named either explicitly MAKEFILE or filename.MAK, the development environment uses NMAKE as the command-line tool to build the project. If you create an external project by choosing Makefile from the Type list in the New dialog box (Project tab), Visual C++ prompts you to open the Project Settings dialog box and explicitly specify the tool that the development environment must run to build the project.

Once you create an external project, you can add files to it, or you can add it to other projects as a subproject. Adding the source files comprising the external project to the project workspace enables you to view those files in FileView, to open them from FileView, to add them to your source-code control system from the development environment, and so on.

If your external project generates an executable file compatible with the Microsoft debugging format, you can debug it from within the development environment.

What do you want to do?

  • Wrap an existing makefile in order to build within the development environment


Optimizing Your Code: Overview

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Visual C++ contains compiler options, pragmas, and code modifiers that you can use to optimize your executable file or dynamic-link library (DLL).

  • Pragmas and Coding Instructions That Affect Optimizations

  • Optimization Switches

For information on how to optimize a DLL, see declspec(dllimport).


Pragmas and Coding Instructions That Affect Optimizations

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Several instructions and pragmas that you can use in your C or C++ code will affect optimization:

  • __asm

  • inline, _inline, or inline

  • #pragma auto_inline

  • #pragma check_stack

  • #pragma function

  • #pragma inline_depth

  • #pragma inline_recursion

  • #pragma intrinsic

  • #pragma optimize


Optimization Switches

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Switch | Description
/G5 | Optimizes for Pentium processor.
/G6 | Optimizes for Pentium Pro processor.
/GB | Optimizes the code created to favor the Pentium. It blends the optimizations for the 80386 (/G3), 80486 (/G4), Pentium (/G5), and Pentium Pro (/G6) options.
/G3 | Optimizes for 80386 processor.
/G4 | Optimizes for 80486 processor.
/Gd | Specifies function calling conventions; not commonly used.
/Ge | Enables stack probes for every function call that requires storage for local variables; not commonly used.
/Gf | Copies identical strings into one location in the executable file.
/GF | Same as /Gf but copies strings into read-only memory; the strings cannot be modified.
/Gh | Calls a function (that you will write) at the beginning of every function call in your program. This will make your executable file larger and slower: a debug tool.
/Gi | Controls the incremental compiler, which compiles only the functions that have changed since the last compile. The compilation is speedier but the executable file is larger: a debug tool.
/Gm | Speeds build if project has many files that have not changed since last compile.
/Gr | Specifies function calling conventions; not commonly used.
/GR | Adds code to check object type at runtime. The executable file will be larger.
/Gs | Controls stack probes; not commonly used.
/GX | Controls whether destructors are called for automatic objects during a stack unwind that is caused by either a Windows NT-based structured exception or a C++ exception.
/Gy | Allows compiler to package individual functions in the form of packaged functions (COMDATs).
/Gz | Specifies function calling conventions; not commonly used.
/O1 | Optimizes for minimum size. Uses /Os as well as other switches.
/O2 | Optimizes for maximum speed. Uses /Ot as well as other switches.
/Oa | Tells compiler that your program does not use “aliasing” (a name that refers to a memory location already referred to by a different name).
/Ob | Controls inline expansion of functions.
/Od | Disables optimizations.
/Og | Eliminates local and global common subexpressions, allows automatic register allocation, and allows loop optimization.
/Oi | Replaces certain function calls with inline function expansion.
/Op | Ensures the precision of floating point operations. This is useful when you are concerned about error propagation and intermediate results of floating point operations. The following topics contain information on understanding floating point operations: IEEE Floating-Point Representation and Microsoft Languages and Why Floating Point Numbers May Lose Precision.
/Os | Favors smaller executable files.
/Ot | Favors faster executable files.
/Ox | Optimizes to use the fastest possible code. However, /O2 is recommended.
/Oy | Suppresses creation of frame pointers on the call stack.
/Ow | Tells compiler that your program does not use aliasing.


Creating a Release Build: Overview

Home | How Do I

This section presents information on why and when you would want to change from a debug build to a release build. It also discusses some of the problems you may encounter when changing from a debug to a release build.

  • Understanding Release Builds

  • Common Problems Switching from Debug to Release Build


Understanding Release Builds

Home | How Do I

You commonly develop your program by using debug builds. By the time you are ready to create a release build:

  • All your code should be in place,

  • Your code’s logic should be correct, and

  • You should have run the profiler to ensure that your algorithms are adequate.

With those things accomplished, you are ready to make your release build. See Select Release Build.

By default, a release build uses optimizations. When you use optimizations to create a release build, the compiler will not produce symbolic debugging information. The absence of symbolic debugging information, along with the fact that code is not generated for TRACE and ASSERT calls, means that the size of your executable file is reduced and will therefore be faster.


Common Problems Switching from Debug to Release Build

Home | How Do I

During development, you will usually build and test with a debug build of your project. If you then build your application for a release build, you may get an access violation.

The list below shows the primary differences between a debug and a release (non-debug) build. There are other differences, but the following are the primary differences that would cause an application to fail in a release build when it works in a debug build.

  • Heap Layout

  • Compilation

  • Pointer Support

  • Optimizations

See the /GZ (Catch Release-Build Errors in Debug Build) compiler option for information on how to catch release build errors in debug builds.

Heap Layout

Heap layout will be the cause of about ninety percent of the apparent problems when an application works in debug, but not release.

When you build your project for debug, you are using the debug memory allocator. This means that all memory allocations have guard bytes placed around them. These guard bytes are placed there to detect a memory overwrite. Because heap layout is different between release and debug versions, a memory overwrite might not create any problems in a debug build, but may have catastrophic effects in a release build.

See Check for Memory Overwrite and Use the Debug Build To Check for Memory Overwrite for more information.

Compilation

Many of the MFC macros and much of the MFC implementation changes when you build for release. In particular, the ASSERT macro evaluates to nothing in release build, so none of the code found in ASSERTs will be executed. See Examine ASSERT Statements for more information.

Some functions are inlined for increased speed in the release build. Optimizations are generally turned on in a release build. A different memory allocator is also being used.

Pointer Support

The lack of debugging information removes the padding from your application. In a release build, stray pointers have a greater chance of pointing to uninitialized memory instead of pointing to debug information.

Optimizations

Depending on the nature of certain segments of code, the optimizing compiler might generate unexpected code. This is the least likely cause of release build problems, but it does arise on occasion. See Optimization Problem for a solution.


Additional Command-Line Build Tools: Overview

Home | How Do I | Details

The tools listed below provide extra ways to view or manipulate your source files or build output.

  • BSCMAKE.EXE builds a browse information file (.BSC) that contains information about the symbols (classes, functions, data, macros, and types) in your program. You view this information in browse windows within the development environment. (A .BSC file can be also be built in the development environment.)

  • DUMPBIN.EXE is a wrapper for LINK /DUMP. It displays information (such as a symbol table) about Common Object File Format (COFF) binary files.

  • EDITBIN.EXE is a wrapper for LINK /EDIT. It is used to modify COFF binary files.

  • LIB.EXE is a wrapper for LINK /LIB. It is used to create and manage a library of COFF object files. It can also be used to create export files and import libraries to reference exported definitions.


Procedures for Compiling and Linking

Home | Overview | Details

  • Set Compiler Options

  • Set Linker Options

  • Set Environment Variables

  • Create an “External” Project

  • Optimize a Program

  • Build the Browse Information File (.BSC)

  • Fix Build Errors

  • Create a Release Build

  • Adjusting the Build Settings and Specifying Custom Build Rules


Set Compiler Options

Home | Overview | Details

Options can be set either in the development environment or on the command line. (See Compiler Reference for a complete list.)

To set compiler options in the development environment

  • Click the Settings command on the Project menu.

    This opens the Project Settings dialog box, which has several tabs (especially the C/C++ tab) on which you can select options.

Setting compiler options outside the development environment

You can set compiler (CL.EXE) options:

  • on the command line

  • in command files

  • in the CL environment variable.

Options specified in the CL environment variable are used every time you invoke CL. If a command file is named in the CL environment variable or on the command line, the options specified in the command file are used. Unlike either the command line or the CL environment variable, a command file allows you to use multiple lines of options and filenames.

Compiler options are processed "left to right", and when a conflict is detected, the last (right-most) option wins. The CL environment variable is processed before the command line, so in any conflicts between CL and the command line, the command line takes precedence.


Compiler Command-Line Syntax

Home | Overview | Details

The CL command line uses the following syntax:

CL [option...] file... [option | file]... [lib...] [@command-file] [/link link-opt...]

The following table describes input to the CL command.

Entry | Meaning
option | One or more CL options. Note that all options apply to all specified source files. Options are specified by either a forward slash (/) or a dash (–). If an option takes an argument, the option’s description documents whether a space is allowed between the option and the arguments. Option names (except for the /HELP option) are case sensitive. See Order of CL Options for more information.
file | The name of one or more source files, .OBJ files, or libraries. CL compiles source files and passes the names of the .OBJ files and libraries to the linker. See CL Filename Syntax for more information.
lib | One or more library names. CL passes these names to the linker.
command-file | A file that contains multiple options and filenames. See CL Command Files for more information.
link-opt | One or more linker options. CL passes these options to the linker.

You can specify any number of options, filenames, and library names, as long as the number of characters on the command line does not exceed 1024, the limit dictated by the operating system.

Note The command-line input limit of 1024 characters is not guaranteed to remain the same in future releases of Windows NT.


CL Filename Syntax

Home | Overview | Details

CL accepts files with names that follow FAT, HPFS, or NTFS naming conventions. Any filename can include a full or partial path. A full path includes a drive name and one or more directory names. CL accepts filenames separated either by backslashes (\) or forward slashes (/). A partial path omits the drive name, which CL assumes to be the current drive. If you don’t specify a path, CL assumes the file is in the current directory.

The filename extension determines how files are processed. C and C++ files, which have the extension .C, .CXX, or .CPP, are compiled. Other files, including .OBJ files, libraries (.LIB), and module-definition (.DEF) files, are passed to the linker without being processed.


Order of CL Options

Home | Overview | Details

Options can appear anywhere on the CL command line, except for the /link option, which must occur last. The compiler begins with options specified in the CL environment variable and then reads the command line from left to right — processing command files in the order it encounters them. Each option applies to all files on the command line. If CL encounters conflicting options, it uses the rightmost option.


CL Command Files

Home | Overview | Details

A command file is a text file that contains options and filenames you would otherwise type on the command line or specify using the CL environment variable. CL accepts a compiler command file as an argument in the CL environment variable or on the command line. Unlike either the command line or the CL environment variable, a command file allows you to use multiple lines of options and filenames.

Options and filenames in a command file are processed according to the location of a command filename within the CL environment variable or on the command line. However, if the /link option appears in the command file, all options on the rest of the line are passed to the linker. Options in subsequent lines in the command file and options on the command line after the command file invocation are still accepted as compiler options. For more information on how the order of options affects their interpretation, see Order of CL Options.

A command file must not contain the CL command. Each option must begin and end on the same line; you cannot use the backslash (\) to combine an option across two lines.

A command file is specified by an at sign (@) followed by a filename; the filename can specify an absolute or relative path.

Example

If the following command is in a file named RESP:

/Og /link LIBC.LIB

and you specify the following CL command:

CL /Ob2 @RESP MYAPP.C

the command to CL is as follows:

CL /Ob2 /Og MYAPP.C /link LIBC.LIB

Note that the command line and the command-file commands are effectively combined.


CL Environment Variable

Home | Overview | Details

Use the CL environment variable to specify files and options without giving them on the command line. The CL environment variable has the following syntax:

SET CL=[ [option] ... [file] ...] [/link link-opt ...]

The CL environment variable is useful if you often specify a large number of files and options when you compile. You can define the files and options you use most often with the CL variable and give only the files and options you need for specific purposes on the command line. The CL environment variable is currently limited to 1024 characters — the command-line input limit in Windows NT.

You cannot use the /D option to define a symbol that uses an equal sign (=). You can substitute the number sign (#) for an equal sign. In this way, you can use the CL environment variable to define preprocessor constants with explicit values (for example, /DDEBUG#1).

For related information, see Set Environment Variables.

Example

The following example of a CL environment variable setting:

SET CL=/Zp2 /Ox /I\INCLUDE\MYINCLS \LIB\BINMODE.OBJ

is equivalent to the following CL command:

CL /Zp2 /Ox /I\INCLUDE\MYINCLS \LIB\BINMODE.OBJ INPUT.C

The following example causes CL to compile the source files FILE1.C and FILE2.C, and then link the object files FILE1.OBJ, FILE2.OBJ, and FILE3.OBJ:

SET CL=FILE1.C FILE2.C
CL FILE3.OBJ

This has the same effect as the following command line:

CL FILE1.C FILE2.C FILE3.OBJ


Optimize a Program

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Visual C++ contains compiler switches that you can use to optimize your executable or DLL.

  • Optimize in Visual C++

  • Control In-line Function Expansion

  • Optimize at the Command Line

  • Debug Optimized Code


Optimize in Visual C++

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

To use the development environment to select optimizations for a project

  1. On the Project menu, click Settings.

  2. In the Project Settings dialog box, click the C/C++ tab.

  3. In the Settings For box, select (highlight) a configuration. For example, select a Release build.

  4. In the Category drop-down box, click Optimizations.

You will now see a drop-down list box titled Optimizations. This list lets you determine how the compiler fine-tunes the performance of your program.

Default

Command line equivalent of /Ot switch.

Disable (Debug)

Command-line equivalent of /Od switch.

Maximize Speed

Command line equivalent of /O2 switch.

Minimize Size

Command line equivalent of /O1 switch.

Customize

The Customize option enables the check boxes that allow you to select optimizations. If you do not check any optimizations, Customize will cause the compiler to make decisions that favor a faster executable. There will be no inline expansion of functions. See Optimization Switches for more information on the options you can choose in the Customize list as well as for optimization switches that you can use that are not in the check list.

For information on functionality in the C/C++ tab of the Project Settings dialog box, see:

  • Control In-line Function Expansion

  • Project Settings dialog box


Control In-line Function Expansion

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Controls which functions become expanded. Expanding a function inline makes the program faster because it does not incur the overhead of calling the function.

Disable

Command line equivalent is the /Ob0 switch.

Only __inline

Command line equivalent is the /Ob1 switch.

Any Suitable

Command line equivalent is the /Ob2 switch.

The compiler treats the inline expansion options and keywords as suggestions. There is no guarantee that functions will be inlined; there is no way to force the compiler to inline a specific function.

You can also use #pragma auto_inline to exclude functions from being considered as candidates for inline expansion.


Optimize at the Command Line

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The CL (Compile and Link) command has switches you can use to effect optimization. See Optimization Switches for a list and description of the switches.

Using the /O2 switch as an example, you might issue

cl /O2 source.c

to maximize your executable for speed.

There is an abbreviated syntax for using more than one switch. If you want to use /Og and /Os, for example, you could specify /Ogs.


Set Linker Options

Home | Overview | Details

Options can be set inside our outside of the development environment. (See Linker Reference for a complete list.)

To set linker options in the development environment

  1. Click the Settings command on the Project menu.

  2. On the Project Settings dialog box, click the Link tab, which shows the available options.

    To pass an object file or standard library (either static or import) to the linker, specify the file name in the Object/Library Modules text box. You can specify an absolute or relative path with the file name, and you can use wildcards in the file name. If you omit the dot (.) and file name extension, the linker assumes .OBJ for the purpose of finding the file. The linker does not use file name extensions or the lack of them to make assumptions about the contents of files; it determines the type of file by examining it and processes it accordingly. For additional information, see LINK Input Files.

Setting linker options outside the development environment

When you run LINK outside the development environment, you can specify input in one or more ways:

  • On the command line

  • Using command files

  • In environment variables

LINK first processes options specified in the LINK environment variable, followed by options in the order they are specified on the command line and in command files. If an option is repeated with different arguments, the last one processed takes precedence.

Options apply to the entire build; no options can be applied to specific input files.


Linker Command-Line Syntax

Home | Overview | Details

To run LINK.EXE, use the following command syntax:

LINK arguments

The arguments include options and filenames and can be specified in any order. Options are processed first, then files. Use one or more spaces or tabs to separate arguments.

On the command line, an option consists of an option specifier, either a dash (–) or a forward slash (/), followed by the name of the option. Option names cannot be abbreviated. Some options take an argument, specified after a colon (:). No spaces or tabs are allowed within an option specification, except within a quoted string in the /COMMENT option. Specify numeric arguments in decimal or C-language notation. Option names and their keyword or filename arguments are not case sensitive, but identifiers as arguments are case sensitive. See Linker Reference for a complete list.

To pass a file to the linker, specify the filename on the command line after the LINK command. You can specify an absolute or relative path with the filename, and you can use wildcards in the filename. If you omit the dot (.) and filename extension, LINK assumes .OBJ for the purpose of finding the file. LINK does not use filename extensions or the lack of them to make assumptions about the contents of files; it determines the type of file by examining it, and processes it accordingly.


LINK Command Files

Home | Overview | Details

You can pass command-line arguments to LINK in the form of a command file. To specify a command file to the linker, use the following syntax:

LINK @commandfile

The commandfile is the name of a text file. No space or tab is allowed between the at sign (@) and the filename. There is no default extension; you must specify the full filename, including any extension. Wildcards cannot be used. You can specify an absolute or relative path with the filename. LINK does not use an environment variable to search for the file.

In the command file, arguments can be separated by spaces or tabs (as on the command line) and by newline characters.

You can specify all or part of the command line in a command file. You can use more than one command file in a LINK command. LINK accepts the command-file input as if it were specified in that location on the command line. Command files cannot be nested. LINK echoes the contents of command files, unless the /NOLOGO option is specified.

See Linker Reference for a complete list of options.

Example

The following command to build a DLL passes the names of object files and libraries in separate command files and uses a third command file for specification of the /EXPORTS option:

link /dll @objlist.txt @liblist.txt @exports.txt


LINK Environment Variables

Home | Overview | Details

LINK uses environment variables as follows:

  • If the LINK variable is defined, LINK processes arguments defined in the variable before it processes the command line. The LINK environment variable can contain any arguments to the linker.

  • If the LIB variable is defined, LINK uses the LIB path when it searches for a file (such as an object or library) specified on the LINK command line or with the /BASE option, or for a .PDB file named in an object. The LIB environment variable can contain one or more path specifications, separated by semicolons (;). You can set the LIB variable within the development environment by selecting the Directories tab in the Options dialog box (available from the Tools menu).

  • If LINK needs to run CVPACK or CVTRES and cannot find it in the same directory as itself, LINK uses the PATH environment variable to look for the tool. CVPACK is required when creating Microsoft-format debugging information. CVTRES is required when linking a .RES file.

  • LINK uses the directory specified in the TMP environment variable when linking OMF or .RES files.

See Linker Reference for a complete list of linker options. Also see Set Environment Variables.


Set Environment Variables

Home | Overview | Details

CL.EXE, LINK.EXE, and other command-line tools require that certain environment variables be set properly. These include PATH, which must point to the \bin subdirectory of your Visual C++ installation, LIB, which must point to \lib, and INCLUDE, which must point to \include.

When you install Visual C++, setup creates a batch file, VCVARS32.BAT, containing commands to modify the PATH, LIB, and INCLUDE environment variables. If these variables haven't been set properly, run VCVARS32.BAT before you compile at the command prompt. VCVARS32.BAT is located in the \bin subdirectory. Note that you do not need to run VCVARS32.BAT if you are compiling your program inside the development environment.

To run VCVARS32.BAT

  1. At the command prompt, change to the \bin subdirectory of your Visual C++ installation.

  2. Run VCVARS32.BAT by typing VCVARS32.

Note VCVARS32.BAT may vary from machine to machine. You should not copy a missing or damaged VCVARS32.BAT file from another installation.

See Also CL Environment Variable, LINK Environment Variables, Using Environment Variables


Using Environment Variables

Environment variables are the variables set by the operating system; they allow for specifying a directory to find project files or copy output files. How environment variables are set differs between Windows 95 and Windows NT.

Environment variables are used in the Project Settings dialog box, especially on these tabs : Custom Build Rules, C/C++, Link, and Resources.

To set environment variables with Windows NT

  1. On the Start menu, point to Settings, then click Control Panel.

  2. In the Control Panel, double click System.

  3. In the System Properties dialog box, click the Environment tab, and specify your environment variable setting, using the User Variables for, Variable, and Value boxes.

  4. Exit the development environment and restart it for the changed environment variable to take effect.

To set environment variables with Windows 95

  1. Add the environment variable to the autoexec.bat file.

  2. Restart Windows 95 for the change to take effect.

Example

Following is an example of using environment variables in a multi-user situation.

Take the project “BldSys.exe,” which uses a library called Mylib.lib. Each user places the Mylib library and include files in a different directory or drive.

To solve this problem, define the environment variable MYLIB.

User 1 sets MYLIB to:

MYLIB = c:\mylib

User 2 sets MYLIB to:

MYLIB = d:\dev\mylib

In the Project Settings dialog box (Project menu), click the C/C++ tab, then click Preprocessor in the Categories list. In the Additional include directories box, type $(MYLIB)\include.

On User 1’s machine, this setting resolves to:

C:\mylib\include

On User 2’s machine, this setting resolves to:

D:\dev\mylib\include

Warning Although the Project Settings dialog box supports environment variables, it is not recommended that environment variables be used except in the Additional include directories box, and in the way suggested. Do not use environment variables to throw switches that change the name or location of output files.

Environment variables are also useful for custom build rules. For example, you can copy output files to a binary directory that could be in any arbitrary location on the user’s machine.

For example, suppose you have a setting you want to specify such as BIN=C:\binnt In the Project Settings dialog box, click the Custom Build tab, then click the first available line in the Build Commands box and type the following:

copy $(TargetName)$(BIN)$(TargetName)

Then, in the Output Files box, add:

$(BIN)$(TargetName)


Create an External Project

You can create a project to run external commands, such as batch files or other executables that you have created outside of the development environment. You can use the resulting project, which runs inside the development environment, to build your program(s).

To add an external project to an existing project workspace

  1. On the File menu, click New.

  2. In the New dialog box, click the Projects tab.

  3. In the Project Name text box, type a name for the project.

  4. From the list of project types, select Makefile.

  5. Choose to either:
    • Create new workspace A separate workspace is created for this external project.

    • Add to current workspace The resulting project is added to the current workspace or to one that you can specify if you check the Dependency of check sbox.
  6. Select any of the available platforms for which you want to create initial Debug and Release configurations.

  7. Click OK.

    Visual C++ prompts you to open the Project Settings dialog box and explicitly specify the tool that the development environment must run to build the project.

  8. From the following list, select the options that apply or fill in the appropriate information in the text boxes.
    • Build Command Line The command line that the operating system executes for this project when you click Build on the Build menu. By default, the system executes Microsoft NMAKE with the /F option followed by the name of the external makefile. You can, however, add any batch or executable filename along with command-line options and input files.

    • Rebuild all options The options added to the command line when you click Rebuild All on the Build menu. By default, the /A option for Microsoft NMAKE is added.

    • Output file name The name of the file that is created when you build the project. This could be an application or static library, for instance.

    • Browse info file name Name of the browse information file to create for this project. It must have the extension .BSC.
  9. Click the Debug tab.

  10. Select the General category from the Category list, and type in the text boxes the information required for debugging. The development environment uses this information when you choose commands such as Go or Step Into on the Debug menu.
    • Executable for debug session The name of the program that the external project builds if you are debugging an executable program, or the name of the executable file that calls a DLL if you are debugging a DLL. If you are debugging an executable file on a remote machine, this executable file on the local machine contains the symbolic debugging information.

    • Working directory The working directory that the application uses when it runs. This directory may be different from the output files directory in the project. It could contain test cases, for instance.

    • Program arguments (for .EXE files) Arguments that need to be passed to the executable file when it starts.

    • Remote executable path and file name The name for the executable file that you are debugging on a remote machine. The location for this executable file is specified relative to the remote machine.
  11. Select the Additional DLLs category from the Category list on the Debug tab, and specify the information required for debugging. The development environment uses this information when you choose commands such as Go or Step Into on the Debug menu.
    • Modules Use this grid control to specify additional DLLs (or EXEs, or OCXs, and so on) to debug. If you check the box to the left of the active line in the grid, the associated debugging symbols will be preloaded. Preloading symbols allows you to set breakpoints before the specified module loads. Use the Browse button, to the right of the active line in the grid, to simplify specifying files, including remote files, that are outside the scope of your system variables.

    • Try to locate other DLLs If this check box is selected, the debugger asks for additional DLLs when debugging begins.


Build the Browse Information File (.BSC)

Home | Overview | Details

There are two steps to creating browse information. First the compiler must make an .SBR file for each source file in your project. Next, BSCMAKE.EXE must concatenate all .SBR files into one .BSC file, which can then be viewed in browse windows in the development environment. See Class Browsing Tasks for information on viewing a .BSC file.

The ClassView pane in the development environment offers another way to browse the .BSC file. See ClassView Topics for more information.

For information on browsing the MFC source code, see MFC: Using the MFC Browse Information File.

To turn on creation of the .SBR files at compile time

  • Add /FR or /Fr to your command-line compile options.

Or

  1. On the Project menu, click Settings to open the Project Settings dialog box.

  2. Click the C/C++ tab. Choose General from the Category list.

  3. Select the Generate browse info check box.

  4. Click the OK button.

To turn on updating of the .BSC file at compile time

  • Call BSCMAKE on the command line or in your makefile.

Or

  1. Open the project if it is not currently open.

  2. On the Project menu, click Settings to open the Project Settings dialog box.

  3. Click the Browse Info tab.

  4. Select the Build browse info file check box.

  5. Choose the OK button.

    Note You must turn on creation of the .SBR files at compile time for this option to work. Turning off the Build browse info file option prevents BSCMAKE from updating the .BSC file, but does not automatically prevent the compiler from creating .SBR files. To bring the .BSC file up to date, turn this update option back on.

You can build your project more quickly if you turn off creation of both the .SBR files and .BSC file. As a default, browse information is turned off. You will not be able to browse current information until you turn the browse options on and build your project again.

Tip If you want to speed up your builds and also want to update your browse information file quickly, turn on creation of .SBR files and turn off updating of the .BSC file. When you want to update your browse information file, turn on updating of the .BSC file and build your project.

Using BSCMAKE from the command line gives you more precise control over the manipulation of browse information files. See BSCMAKE Reference for more information. For background information, see How BSCMAKE Builds a .BSC File.


Increasing Efficiency with BSCMAKE

Home | Overview | Details

The building process can require large amounts of time, memory, and disk space. However, you can reduce these requirements by creating a smaller .BSC file and by avoiding unreferenced definitions.

Making a Smaller Browse Information File

Smaller browse information files take less time to build, use less disk space, reduce the risk of BSCMAKE running out of memory, and run faster in the Browse window. You can use one or more of the following methods to create a smaller file:

  • Use BSCMAKE command-line options to exclude information from the browse information file.

  • Omit local symbols in one or more .SBR files when compiling or assembling.

  • If an object file does not contain information that you need for your current stage of debugging, omit its .SBR file from the BSCMAKE command when rebuilding the browse information file.

Save Build Time and Disk Space by Eliminating Unreferenced Definitions

Unreferenced definitions cause .SBR files to take up more disk space and cause BSCMAKE to run less efficiently. The compiler automatically packs .SBR files to remove unreferenced definitions. The /Zn (Turn Off SBRPACK) option prevents this packing. You can increase efficiency of disk space and BSCMAKE speed by not using /Zn and allowing the compiler to pack the .SBR files.


Remove Intermediate Files

You can delete all executable (.EXE), dynamic link library (.DLL), and Control (.OCX) files by using the Clean command. This command does not remove precompiled header (.PCH) files because the initial generation of .PCH files is time consuming. If the project is a server project that has been registered on the system, the registry entries will not be cleaned up.

Removing the files forces the development environment to build these files if you subsequently click the Build command.

To remove intermediate files

  1. On the Build menu, click Set Active Configuration.

  2. In the Project configurations list, select a project configuration and click OK.

  3. On the FileView pane in the Project Workspace window, select the project.

  4. With the mouse pointer over the selected project, click the right mouse button to display the pop-up menu, and click Clean.

Note This procedure deletes the intermediate and output files from the intermediate files directory associated with the selected configuration.


Fix Build Errors

Home | Overview

When you compile and link your program in the development environment, the Output window is automatically opened, and information about the build is displayed there, including error and warning messages. The Output window has two ways of helping you find and fix the causes of error and warning messages: it connects you to the line of code where the message is generated, and it connects you to a help topic that gives additional information about the message.

To see the code that generates a diagnostic message

  • Double-click a diagnostic message in the Output window.

    The appropriate source file opens, and a pointer shows the line which generates the diagnostic message.

To get help on an error message

  1. Click the mouse pointer on the error message number (for example, C1201) in the Output window.

  2. Press F1.

    The topic corresponding to the selected error number is opened in the help window.

If you do not build in the development environment, you can access information on diagnostic messages by using the Search dialog box available from the Help menu. Type the error message number in the search box and click the List Topics button, then click Display.

See Also Common Problems Switching from Debug to Release Build


Create a Release Build

Home | Overview

This section discusses how you can create the release build of your program and how to fix any problems that arise with your program as a result of switching to a release build.

  • Select Release Build

  • Fix Release Build Problems

  • Mixing Debug and Release Builds in an Application


Select Release Build

Home | Overview

To generate a release build of your program

  1. Select Win32 Release from the Select Active Configuration drop-down list on the Build toolbar.

  2. On the Build menu, click Build project.exe.


Fix Release Build Problems

Home | Overview

If your code generates compile errors after switching from debug build to release build, there are some areas you should check.

  • Examine ASSERT Statements

  • Use the Debug Build To Check for Memory Overwrites

  • Turn on Generation of Debug Information for the Release Build

  • Check for Memory Overwrite

  • Optimization Problem

See Also Fix Build Errors


Examine ASSERT Statements

Home | Overview

Suppose that when you run the debug version of your MFC application, there are no problems. However, the release version of the same application crashes, returns incorrect results, and/or exhibits some other abnormal behavior.

This problem can be caused when you place important code in an ASSERT statement to verify that it performs correctly. Because ASSERT statements are commented out in a release build of an MFC program, the code does not run in a release build.

If you are using ASSERT to confirm that a function call succeeded, consider using VERIFY instead. The VERIFY macro evaluates its own arguments in both debug and release builds of the application.

Another preferred technique is to assign the function's return value to a temporary variable and then test the variable in an ASSERT statement.

Examine the following code fragment:

char *buf;
ASSERT(buf = (char *) calloc( 20, sizeof(char) ));
strcpy( buf, "Hello, World" );
free( buf );

This code runs perfectly in a debug version of an MFC application. If the call to calloc( ) fails, a diagnostic message that includes the file and line number appears. However, in a retail build of an MFC application:

The call to “calloc( )” never occurs, leaving "buf" uninitialized, or

“strcpy( )" copies "Hello, World" into a random piece of memory, possibly crashing the application or hanging the system, or

"free()" attempts to free memory that was never allocated.

To use ASSERT correctly, the code sample should be changed to the following:

char *buf;
buf = (char *) calloc( 20, sizeof(char) );
ASSERT( buf != NULL );
strcpy( buf, "Hello, World" );
free( buf );

Or, you can use VERIFY instead:

char *buf;
VERIFY(buf = (char *) calloc(20, sizeof(char) ));
strcpy( buf, "Hello, World" );
free( buf );


Use the Debug Build To Check for Memory Overwrite

Home | Overview

First, switch back and rebuild your project for debug. Go to the very beginning of your application's InitInstance function and add the following line:

afxMemDF |= checkAlwaysMemDF;

The debug memory allocator puts guard bytes around all memory allocations. However, these guard bytes don't do any good unless you check whether they have been changed (which would indicate a memory overwrite). Otherwise, this just provides a buffer that might in fact allow you to get away with a memory overwrite.

By turning on the checkAlwaysMemDF, you will force MFC to make a call to the AfxCheckMemory function every time a call to new or delete is made. If a memory overwrite was detected, it will generate a TRACE message that looks similar to the following:

Damage Occurred! Block=0x5533

If you see one of these messages, you need to step through your code to determine where the damage occurred. To isolate more precisely where the memory overwrite occurred, you can make explicit calls to AfxCheckMemory yourself. For example:

ASSERT(AfxCheckMemory());
    DoABunchOfStuff();
    ASSERT(AfxCheckMemory());

If the first ASSERT succeeds and the second one fails, it means that the memory overwrite must have occurred in the function between the two calls.

Depending on the nature of your application, you may find that afxMemDF causes your program to run too slowly to even test. The afxMemDF variable causes AfxCheckMemory to be called for every call to new and delete. In that case, you should scatter your own calls to AfxCheckMemory( ) as shown above, and try to isolate the memory overwrite that way.


Turn on Generation of Debug Information for the Release Build

Home | Overview

You can debug a release build.

To enable debugging of a release build, change the following release build options

  1. On the Project menu, click Settings, and then click the C/C++ tab.

  2. In the Category drop-down box, click General.

  3. In the Debug info drop-down box, click Program Database.

  4. In the Optimizations drop-down box, click Disable (Debug).

  5. On the Link tab, select Generate Debug Info.

These selections correspond to the /Od and /Zi options, which turn off optimizations and place debug information in the build.

After doing this, rebuild and test your program. If at this point the program works fine, then it is still possible that you have a memory overwrite, but it is also possible that the optimizations are causing problems on a particular piece of code. To isolate that code, see Optimization Problem.

The purpose of turning off optimizations is to help you in debugging the application. With optimizations on, the debugger won't necessarily be able to show you the correct source code and debug information.

You can now debug your release build application. Finding the problem is now a matter of stepping through the code (or of using Just-In-Time debugging) until you find where the failure occurs, and then determine the incorrect parameters or code.


Check for Memory Overwrite

Home | Overview

If you get an access violation on a call to a heap manipulation function, it is possible that your program has corrupted the heap. A common symptom of this situation would be:

Access Violation in _searchseg

The _heapchk function is available in both debug and release builds (Windows NT only) for verifying the integrity of the run-time library heap. _heapchk can be used in much the same way as the AfxCheckMemory function to isolate a heap overwrite, for example:

if(_heapchk()!=_HEAPOK)
   DebugBreak();

If this function ever fails, then it is a matter of isolating at which point the heap got corrupted.


Optimization Problem

Home | Overview

Optimizing compilers can sometimes change your code to something you wouldn't expect. If you find that the application works when you build for release without optimizations, but not when you build for release with optimizations, this might be the case.

If you suspect that a particular portion of your code is not being optimized correctly and is causing problems in the compilation or running of your program, you can bracket the offending code with

#pragma optimize("", off)

and

#pragma optimize("", on)

Developers have also been able to trace the bad code being generated when optimizations are on by looking at the actual assembly code generated for a function.


Mixing Debug and Release Builds in an Application

Home | Overview

When building large Microsoft Foundation Class (MFC) applications, the debug information can take up a lot of disk space. To reduce the size of the application, there are several methods by which you can remove the debugging information from some of the modules in the project and/or from the MFC libraries themselves. Moreover, the development environment supports per-file build rules, which can greatly reduce the amount of debug information that is generated for an application.

The following are among the methods available to reduce the amount of debugging information included in a project:

  • Use Per-File Build Options

  • Build the Debug MFC Libraries with Reduced CodeView Information

  • Build the Debug MFC Libraries Without CodeView Information

  • Use the Full Debug MFC Libraries with Only Selected Debug Modules

  • Use an External Makefile to Mix Release and Debug Information


Use Per-File Build Options

Home | Overview

You can specify the /Zd (Line Numbers Only) option, among others, for specific files. Doing so can greatly reduce the amount of debug information per module.

To set the /Zd option

  1. On the Project menu click Settings to open the Project Settings dialog box.

  2. Click the desired file in your Debug target's tree view to highlight it.

  3. Click the C/C++ tab.

  4. With the General category selected, click Line Numbers Only in the Debug info list box.


Build the Debug MFC Libraries with Reduced CodeView Information

Home | Overview

Try rebuilding the MFC libraries using the /Zi compiler switch instead of /Z7. The /Zi option builds a program database (.PDB) file for the entire library that contains all of the symbolic type information. Each time the compiler generates type information for a new symbol when compiling the source files, it checks the .PDB file to see whether this type is already present. If so, the type is not added.


Build the Debug MFC Libraries Without CodeView Information

Home | Overview

This is the one of the easiest methods for reducing the size of your debug executable file. The only thing lost by using this method is the ability to step into the MFC code itself. All other debug facilities, such as ASSERTs and TRACEs, remain.

The following command builds the medium-memory model debug MFC library without CodeView information for Windows (NAFXCWD.LIB):

NMAKE MODEL=M TARGET=W DEBUG=1 CODEVIEW=0


Use the Full Debug MFC Libraries with Only Selected Debug Modules

Home | Overview

This method allows you to step into the MFC source code as well as providing the other debug facilities. This makes use of both the Debug and Release modes of the Visual C++ makefile, thus making necessary the changes described below (and also making a "rebuild all" necessary when a full release build is required):

  1. On the Build menu, click Set Active Configuration, and then click the release version of the project in the Set Active Project Configuration dialog box.

  2. On the Project menu, click Settings to open the Project Settings dialog box.

  3. In the Microsoft Foundation Classes list box in the General tab, click Use MFC in a Static Library.

  4. In the Category list box in the C/C++ tab, click Preprocessor. Change "NDEBUG" to "_DEBUG" in the Preprocessor definitions text box.

  5. In the Category list box in the Link tab, click Input. Type NAFXCWD.LIB in the Object/library modules text box.

  6. Click OK to save the new build options and close the Project Settings dialog box.

  7. On the Build menu, click Rebuild All. This removes all debug information from your modules, but does not affect the MFC library.

  8. For each project file in which you want to include debug information, follow the steps of Use Per-File Build Options, specifying the desired degree of debug information.

    Note If you are using an AppWizard-generated application or have precompiled headers, you either have to recompile them before compiling the other modules or turn off the precompiled headers. Warning C4650 and error message C2855 are returned if this is not done correctly.

  9. On the Build menu, click Build <EXE name> to rebuild project files that are out of date.

This includes debug symbols for the selected modules. You are able to set breakpoints only within modules you have compiled using debug information. If you need to reduce the executable size even further, you can use the MFC debug libraries as described in Build the Debug MFC Libraries Without CodeView Information.


Use an External Makefile to Mix Release and Debug Information

Home | Overview

This technique eliminates the need to alter the effects of a release build. It also eliminates the need to manually recompile each module to keep the object files up to date. However, you can no longer change compile and link options from within the development environment. The makefile has to be maintained manually. The important thing to keep in mind is that if you want to link with the debug MFC libraries you must have the _DEBUG flag defined for every module. Conversely, if you want the release MFC libraries, you must have NDEBUG defined. For more information on writing external makefiles, see NMAKE Reference.


Frequently Asked Questions on Compiling and Linking

Home | Overviews: Compiling and Linking

  1. What compiler options are available?

  2. What linker options are available?

  3. What other tools are available to help with my project?

  4. How do I optimize my code?

  5. Why is the CL command not recognized when I compile my program at the command prompt?

  6. What does the build process do?

  7. I need info on building on the command line.

  8. How can I browse the MFC source code?

  9. How do I change the default output directories?

  10. Can I open a makefile in the development environment if the makefile was not made there?

  11. How do I build my project?

  12. What's the difference between debug and release builds?

  13. I want to browse my project. How do I set that up?

  14. How do I use precompiled header files?


How do I change the default output directories?

When you build a project, you can select the directories in which to put the intermediate and final output files. By putting these files in different directories, you can maintain copies of the same files built in different ways — for instance, the Debug and the Release versions of your project.

To select output directories

  1. On the Project menu, click Settings.

  2. In the Settings For pane, select the item for which you want to set directories.

    If you select the project configuration, you can set both intermediate and output directories; if you select a file, you can set only the intermediate directory.

  3. Select the General tab.

  4. In the Intermediate Files text box, type the directory name for the intermediate files (.OBJ files, for instance).

  5. If you are setting directories for the project level, type the directory name for the final output files (.EXE files or .CLASS, for instance) in the Output Files text box.


Details About Compiling and Linking

Home | How Do I | Overview

Visual C++ mechanisms for building

  • Build Commands in Visual C++

  • Project Settings Dialog Box

Switches and command-line tools related to building

  • NMAKE Reference

  • Compiler Option Reference

  • Linker Option Reference

  • The Preprocessor

  • BSCMAKE Reference

  • LIB Reference

  • EDITBIN Reference

  • DUMPBIN Reference

Miscellaneous

  • Decorated Names

  • Module-Definition (.DEF) Files


Build Commands in Visual C++

Home | How Do I | Overview

The selected build-related commands discussed below are found on the Build menu. For related information, see Compiler Options and Linker Options. Most build settings are made in the Project Settings dialog box, available from the Project menu

Build menu command | Action
Batch Build | Builds multiple projects.
Build | Compiles and links the project, processing all files that have changed since the last build. Results are displayed in the Output window. Your program will be ready to run, providing it has no fatal errors.
Compile | Runs the compiler on the select source file(s). Results are displayed in the Output window.
Configurations | Specifies a particular project configuration (such as Release or Debug).
Execute | Runs the program that has been built.
Export Makefile | Exports a buildable project in external makefile format.
Rebuild All | Builds all files in the project, processing files regardless of whether they have changed since the last build.
Stop Build | Stops the build.
Update All Dependencies | Updates dependencies for the selected project(s).


Project Settings Dialog Box

Home | How Do I | Overview

Set compiler and linker options in the Project Settings dialog box, which you can open by clicking Settings on the Project menu.

The Reset button resets the project settings of a project or a file to the settings that existed when the project or file was created. This button is available if both of the following conditions are met:

  • A single project or a single file is selected in the Settings For pane of the Project Settings dialog box.

  • The settings of the selection have changed.

The Reset button is not available when multiple projects or files are selected.

For information on the build options available in the Project Settings dialog box, either type an option name in the Search dialog box (Help menu) or see Set Compiler Options and Set Linker Options for overview lists.

Applying settings to particular entities

In the Project Settings dialog box you can specify all the settings for your build. You can specify settings for particular source files, for a version (release or debug), or for the project as a whole. The mechanism for determining this distinction is the left half of the dialog box, which is labeled Settings For.

Determining which settings are in effect

The Common | Project | Source File Options text box, at the bottom right of the Project Settings dialog box, displays the compiler options that are currently selected. The options are displayed using their command-line-equivalent names, such as /G5.

The name of this text box changes depending on what is selected in the Settings For pane in the left half of the dialog box. When a project is selected in Settings For, the text box is named Project Options. When a source file is selected, the text box is named Source File Options. When multiple projects or files are selected, the text box is named Common Options, and it displays the options that are common to the selections.

You cannot type in the text box when it is named Common Options. However, when it is named Project Options or Source File Options, the text box accepts any option that is available from the C/C++ tab. It also accepts those compiler options that are otherwise available only from the command line.

You are responsible for the accuracy of any option you type in the text box. If an option is recognized as one that can be set using a dialog box control, the dialog box control is changed to reflect the option. However, if the option is not recognized, it is left in the options string and passed to the compiler as is.


Compiler Reference

Home | Overview | How Do I

CL.EXE is a 32-bit tool that controls the Microsoft C and C++ compilers and linker. The compilers produce Common Object File Format (COFF) object (.OBJ) files. The linker produces executable (.EXE) files or dynamic-link libraries (DLLs).

For information on specifying options, see Set Compiler Options. Other topics covered in this section are Fast Compilation and CL Invokes the Linker.

To compile without linking, use /c on the command line or click the Compile command on the Build menu.

The following is a comprehensive, alphabetic list of options for the compiler (CL.EXE). Click any option name for specific information about it. Also see the compiler options listed by category of purpose.

Option name and arguments | Purpose
/C | Preserves comments during preprocessing
/c | Compiles without linking
/D name[= | # [{string | number}] ] | Defines constants and macros
/E | Copies preprocessor output to standard output
/EH{s|a}[c][-] | Specifies the model of exception handling
/EP | Copies preprocessor output to standard output
/F number | Sets stack size
/FA[c|s] | Creates a listing file
/Fa | Sets listing file name
/Fd filename | Renames program database file
/FD | Generate file dependencies
/Fe filename | Renames the executable file
/FI filename | Preprocesses the specified include file
/Fm[filename] | Creates a map file
/Fo filename | Creates an object file
/Fp filename | Specifies a precompiled header file name
/FR[filename] /Fr[filename] | Generate browser files
/G3 | Optimizes code to favor the 386 processor. Phased out in Visual C++ 5.0, the compiler will ignore this option
/G4 | Optimizes code to favor the 486 processor. Phased out in Visual C++ 5.0, the compiler will ignore this option
/G5 | Optimizes code to favor the Pentium processor
/G6 | Optimizes code to favor the Pentium Pro processor
/GA | Optimizes code for Windows application
/GB | Optimizes code to favor the Pentium processor. Blends optimizations for the 80386 (/G3), 80486 (/G4), Pentium (/G5), and Pentium Pro (/G6) options.
/GD | Optimizes code for Windows DLL
/Gd | Uses the __cdecl calling convention
/Ge | Activates stack probes
/GF /Gf | Enable string pooling
/Gh | Calls hook function, __penter
/Gi | Enables incremental compilation
/Gm | Enables minimal rebuild
/GR | Enables run-time type information (RTTI)
/Gr | Uses the __fastcall calling convention
/Gs size | Controls stack probes
/GT | Supports fiber safety for data allocated using static thread-local storage.
/GX[–] | Enables synchronous exception handling
/Gy | Enables function-level linking
/GZ | Catch release-build errors in debug build
/Gz | Uses the __stdcall calling convention
/H number | Restricts the length of external (public) names
/HELP | Lists the compiler options
/I directory | Searches a directory for include files
/J | Changes the default char type
/LD | Creates a dynamic-link library
/LDd | Creates a debug dynamic-link library
/link option | Passes the specified option to LINK
/MD | Creates a multithreaded DLL, using MSVCRT.LIB
/MDd | Creates a debug multithreaded DLL, using MSVCRTD.LIB
/ML | Creates a single-threaded executable file, using LIBC.LIB
/MLd | Creates a debug single-threaded executable file, using LIBCD.LIB
/MT | Creates a multithreaded executable file, using LIBCMT.LIB
/MTd | Creates a debug multithreaded executable file, using LIBCMTD.LIB
/nologo | Suppresses display of sign-on banner
/O1 | Creates small code
/O2 | Creates fast code
/Oa | Assumes no aliasing
/Ob | Controls inline expansion
/Od | Disables optimization
/Og | Uses global optimizations
/Oi | Generates intrinsic functions
/Op | Improves floating-point consistency
/Os | Favors small code
/Ot | Favors fast code
/Ow | Assumes aliasing across function calls
/Ox | Uses maximum optimization (/Ob1gity /Gs)
/Oy | Omits frame pointer
/Qlf | Generates additional debugging information for kernal-mode device drivers.
/QI0f | Performs Pentium 0x0f erratum fix
/QIfdiv[–] | Performs Pentium FDIV erratum fix
/P | Writes preprocessor output to a file
/Tc filename /TC | Specifies a C source file
/Tp filename /TP | Specifies a C++ source file
/U symbol | Removes a predefined macro
/u | Removes all predefined macros
/V | Sets the version string
/vd{0|1} | Suppresses or enables hidden vtordisp class members
/vmb | Uses best base for pointers to members
/vmg | Uses full generality for pointers to members
/vmm | Declares multiple inheritance
/vms | Declares single inheritance
/vmv | Declares virtual inheritance
/W level | Sets warning level
/w | Disables all warnings
/X | Ignores the standard include directory
/Yc[filename] | Creates a precompiled header file
/Yd | Places complete debugging information in all object files
/Yu[filename] | Uses a precompiled header file during build
/YX | Automates precompiled header
/Z7 | Generates C 7.0–compatible debugging information
/Za | Disables language extensions
/Zd | Generates line numbers
/Ze | Enables language extensions
/Zg | Generates function prototypes
/Zi | Generates complete debugging information
/ZI | Includes debug information in a program database compatible with Edit and Continue.
/Zl | Removes default library name from .OBJ file
/Zm number | Sets the compiler's memory allocation limit
/Zn | Turns off SBRPACK for .SBR files
/Zp n | Packs structure members
/Zs | Checks syntax only


Compiler Options Listed by Category

Home | Overview | How Do I

Optimization:

/O1 | Creates small code
/O2 | Creates fast code
/Oa | Assumes no aliasing
/Ob | Controls inline expansion
/Od | Disables optimization
/Og | Uses global optimizations
/Oi | Generates intrinsic functions
/Op | Improves floating-point consistency
/Os | Favors small code
/Ot | Favors fast code
/Ow | Assumes aliasing across function calls
/Ox | Uses maximum optimization (/Ob1gity /Gs)
/Oy | Omits frame pointer

Code Generation:

/EH{s|a}[c][-] | Specifies the model of exception handling
/G3 | Optimizes code to favor the 386 processor. Phased out in Visual C++ 5.0, the compiler will ignore this option
/G4 | Optimizes code to favor the 486 processor. Phased out in Visual C++ 5.0, the compiler will ignore this option
/G5 | Optimizes code to favor the Pentium
/G6 | Optimizes code to favor the Pentium Pro
/GA | Optimizes code for Windows application
/GB | Optimizes code to favor the Pentium processor. Blends optimizations for the 80386 (/G3), 80486 (/G4), Pentium (/G5), and Pentium Pro (/G6) options.
/Gd | Uses the __cdecl calling convention
/Ge | Activates stack probes
/GF /Gf | Enable string pooling
/Gh | Calls hook function, __penter
/Gi | Enables incremental compilation
/Gm | Enables minimal rebuild
/GR | Enables run-time type information (RTTI)
/Gr | Uses the __fastcall calling convention
/Gs size | Controls stack probes
/GT | Supports fiber safety for data allocated using static thread-local storage
/GX[–] | Enables synchronous exception handling
/Gy | Enables function-level linking
/Gz | Uses the __stdcall calling convention
/MD | Creates a multithreaded DLL, using MSVCRT.LIB
/MDd | Creates a debug multithreaded DLL, using MSVCRTD.LIB
/ML | Creates a single-threaded executable file, using LIBC.LIB
/MLd | Creates a debug single-threaded executable file, using LIBCD.LIB
/MT | Creates a multithreaded executable file, using LIBCMT.LIB
/MTd | Creates a debug multithreaded executable file, using LIBCMTD.LIB

Output Files:

/FA[c|s] /Fa | Creates a listing file Sets listing file name
/Fd filename | Renames program database file
/FD | Generate file dependencies
/Fe filename | Renames the executable file
/Fm[filename] | Creates a map file
/Fo filename | Creates an object file
/Fp filename | Specifies a precompiled header file name
/FR[filename] /Fr[filename] | Generate browser files

Debugging:

/Qlf | Generates additional debugging information for kernal-mode device drivers.
/GZ | Catch release-build errors in debug build
/Yd | Places complete debugging information in all object files
/Z7 | Generates C 7.0–compatible debugging information
/Zd | Generates line numbers
/Zi | Generates complete debugging information

Preprocessor:

/C | Preserves comments during preprocessing
/D name[= | # [{string | number}] ] | Defines constants and macros
/E | Copies preprocessor output to standard output
/EP | Copies preprocessor output to standard output
/Fl filename | Preprocesses the specified include file
/I directory | Searches a directory for include files
/P | Writes preprocessor output to a file
/U symbol | Removes a predefined macro
/u | Removes all predefined macros
/X | Ignores the standard include directory
/ZI | Includes debug information in a program database compatible with Edit and Continue.

Language:

/vd{0|1} | Suppresses or enables hidden vtordisp class members
/vmb | Uses best base for pointers to members
/vmg | Uses full generality for pointers to members
/vmm | Declares multiple inheritance
/vms | Declares single inheritance
/vmv | Declares virtual inheritance
/Za | Disables language extensions
/Ze | Enables language extensions
/Zg | Generates function prototypes
/Zl | Removes default library name from .OBJ file
/Zp n | Packs structure members
/Zs | Checks syntax only

Linking:

/F number | Sets stack size
/LD | Creates a dynamic-link library
/LDd | Creates a debug dynamic-link library
/link option | Passes the specified option to LINK
/MD | Compiles to create a multithreaded DLL, using MSVCRT.LIB
/MDd | Compiles to create a debug multithreaded DLL, using MSVCRTD.LIB
/ML | Compiles to create a single-threaded executable file, using LIBC.LIB
/MLd | Compiles to create a debug single-threaded executable file, using LIBCD.LIB
/MT | Compiles to create a multithreaded executable file, using LIBCMT.LIB
/MTd | Compiles to create a debug multithreaded executable file, using LIBCMTD.LIB

Precompiled Header Files:

/Yc[filename] | Creates a precompiled header file
/Yd | Places complete debugging information in all object files
/Yu[filename] | Uses a precompiled header file during build
/YX | Automates precompiled header

Miscellaneous:

/c | Compiles without linking
/H number | Restricts the length of external (public) names
/HELP | Lists the compiler options
/J | Changes the default char type
/nologo | Suppresses display of sign-on banner
/Tc filename /TC | Specifies a C source file
/Tp filename /TP | Specifies a C++ source file
/V | Sets the version string
/W level /w | Sets warning level
/Zm number | Sets the compiler's memory allocation limit
/Zn | Turns off SBRPACK for .SBR files


Fast Compilation

Home | Overview | How Do I | Compiler Options

One way to speed compilation is to use minimal rebuild and incremental compilation. With minimal rebuild, a feature specific to C++, the compiler can recompile a source file only if it is dependent on changes to a class in a header file. With incremental compilation, the compiler recompiles only those functions that have changed since the last compile time.

Another way to speed compilation is to use the precompiled header options. For a full discussion, see Creating Precompiled Header Files.


CL Invokes the Linker

Home | Overview | How Do I | Compiler Options

CL automatically invokes the linker after compiling unless the /c option is used. CL passes to the linker the names of .OBJ files created during compiling and the names of any other files specified on the command line. The linker uses the options listed in the LINK environment variable. You can use the /link option to specify linker options on the CL command line. Options that follow the /link option override those in the LINK environment variable. The options in the following table suppress linking.

Option | Description
/c | Compile without linking
/E, /EP, /P | Preprocess without compiling or linking
/Zg | Generate function prototypes
/Zs | Check syntax

For further details about linking, see Linker Option Reference.

Example

Assume that you are compiling three C source files: MAIN.C, MOD1.C, and MOD2.C. Each file includes a call to a function defined in a different file:

  • MAIN.C calls the function func1 in MOD1.C and the function func2 in MOD2.C.

  • MOD1.C calls the standard library functions printf and scanf.

  • MOD2.C calls graphics functions named myline and mycircle, which are defined in a library named MYGRAPH.LIB.

To build this program, compile with the following command line:

CL MAIN.C MOD1.C MOD2.C MYGRAPH.LIB

CL first compiles the C source files and creates the object files MAIN.OBJ, MOD1.OBJ, and MOD2.OBJ. The compiler places the name of the standard library in each .OBJ file. For more details, see Use Run-Time Library.

CL passes the names of the .OBJ files, along with the name MYGRAPH.LIB, to the linker. The linker resolves the external references as follows:

  1. In MAIN.OBJ, the reference to func1 is resolved using the definition in MOD1.OBJ; the reference to func2 is resolved using the definition in MOD2.OBJ.

  2. In MOD1.OBJ, the references to printf and scanf are resolved using the definitions in the library that the linker finds named within MOD1.OBJ.

  3. In MOD2.OBJ, the references to myline and mycircle are resolved using the definitions in MYGRAPH.LIB.


/C (Preserve Comments During Preprocessing)

Home | Overview | How Do I | Compiler Options

This option preserves comments during preprocessing when used with the /E, /P, or /EP option, and is not valid if /E, /P, or /EP is not used. If you do not specify the /C option, the preprocessor does not pass source-file comments to its output file.


/c (Compile Without Linking)

Home | Overview | How Do I | Compiler Options

This option suppresses the implicit call to LINK that normally occurs; only .OBJ files are created. LINK must then be called explicity with the proper files and options to perform the linking phase of the build that will generate a final executable file, DLL, or library.

The /c option is used by default for any internal project created in the development environment (see the Compile command on the Build menu).

Example

The following example creates the object files FIRST.OBJ and SECOND.OBJ. The file THIRD.OBJ is ignored.

CL /c FIRST.C SECOND.C THIRD.OBJ

In order to create an executable file, for example, you would next need to issue the following line:

LINK firsti.obj second.obj third.obj /OUT:filename.exe


/D (Preprocessor Definitions)

Home | Overview | How Do I | Compiler Options

This option defines symbols or constants for your source file.

Command Line | Project Settings | Description
/Dname[= | # [{string | number}] ] | Preprocessor Definitions | With one exception, defining symbols and constants with this option has the same effect as using a #define preprocessor directive at the beginning of your source file. If you use /D, quotes on the command line will be stripped whereas they are retained in a #define statement. The constant is defined until either an #undef directive in the source file removes the definition, or the compiler reaches the end of the file.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Preprocessor in the Category box.

Note The behavior of the Preprocessor Definitions text box differs from the behavior of the /D command-line option; you cannot use either an equal sign (=) or a number sign (#) to assign a value to symbols typed in the text box.

Use the constants created by the compiler and this option in combination with either the #if or #ifdef directive to compile source files conditionally.

You can redefine a keyword, identifier, or numeric constant that has been defined in a source file. If a constant defined in a /D option is also defined within the source file, CL uses the definition on the command line until it encounters a redefinition in the source file.

You can undefine a previous definition. To do so, use the /D option with a keyword, identifier, or numeric constant, and append an equal sign (=) followed by a space.

You cannot set the CL environment variable to a string that contains an equal sign. To use /D with the CL environment variable, specify a number sign instead of an equal sign:

SET CL "/DTEST#0"

Examples

The following command defines the symbol DEBUG in TEST.C:

CL /DDEBUG  TEST.C

The following command removes all occurrences of the keyword __far in TEST.C:

CL /D__far=  TEST.C

See Also Undefine Symbols (/U, /u)


/E (Preprocess to stdout)

Home | Overview | How Do I | Compiler Options

This option preprocesses C and C++ source files and copies the preprocessed file to the standard output device. The output is identical to the original source file, except that all preprocessor directives are carried out, macro expansions are performed, and comments are removed. You can use the /C option with /E to preserve comments in the preprocessed output.

Use the /E option when you want to resubmit the preprocessed listing for compilation. Unlike the /EP option, /E adds #line directives to the output. The #line directives are placed at the beginning and end of each included file and around lines removed by preprocessor directives that specify conditional compilation. The #line directives renumber the lines of the preprocessed file so that errors generated during later stages of processing refer to the line numbers of the original source file rather than to the preprocessed file. Use the /EP option to suppress #line directives.

The /E option suppresses compilation. It also suppresses the output files from the /FA, /Fa, and /Fm options.

Note You cannot use precompiled headers with the /E option.

The following table summarizes the actions of the /E, /EP, and /P options.

Option | Preprocessor output includes #line directives? | Output sent to
/E | Yes | stdout
/P | Yes | .i file
/EP | No | stdout
/E /EP | No | stdout
/P /EP | No | .i file

Example

The following command creates a preprocessed file from the source file ADD.C. It preserves comments and adds #line directives. The output is displayed:

CL /E /C ADD.C


/EH (Exception Handling Model)

Home | Overview | How Do I | Compiler Options

Syntax

/EH{s|a}[c][-]

This option specifies the model of exception handling to be used by the compiler.

  • Use /EHs to specify the synchronous exception handling model.

  • Use /EHa to specify the asynchronous exception handling model.

The /EHc option requires that /EHs, /EHa, or /GX is specified. It tells the compiler to assume that extern C functions never throw an exception.

The option can be cleared by the symbol “-”. For example: /EHsc- is interpreted as /EHs /EHc- , and is equivalent to /EHs.

See Synchronous Exception Handling for more information.


/EP (Preprocess to stdout Without #line Directives)

Home | Overview | How Do I | Compiler Options

The /EP option is similar to the /E option. It preprocesses C and C++ source files and copies the preprocessed file to the standard output device. The output is identical to the original source file, except that all preprocessor directives are carried out, macro expansions are performed, and comments are removed. You can use the /C option with /EP to preserve comments in the preprocessed output. Unlike /E, however, /EP does not add #line directives to the output.

The /EP option suppresses compilation. It also suppresses the output files from the /FA, /Fa, and /Fm options.

The following table summarizes the actions of the /E, /EP, and /P options.

Option | Preprocessor output includes #line directives? | Output sent to
/E | Yes | stdout
/P | Yes | .i file
/EP | No | stdout
/E /EP | No | stdout
/P /EP | No | .i file

Example

The following command creates a preprocessed file from the source file ADD.C. It preserves comments, but does not insert #line directives. The output is displayed:

CL /EP /C ADD.C


/F (Set Stack Size)

Home | Overview | How Do I | Compiler Options

The /Fnumber option sets the program stack size to a specified number of bytes. If you don’t specify this option, a stack size of 1 MB is used by default. The number argument can be in decimal or C-language notation. The argument can range from a lower limit of one to the maximum stack size accepted by your linker. (The linker rounds up the specified value to the nearest 4 bytes.) A space is optional between /F and number.

You can also set stack size by using the linker’s /STACK option or by running EDITBIN on an .EXE file.

You may want to increase the stack size if your program gets stack-overflow diagnostic messages.


Output-File (/F) Options

Home | Overview | How Do I | Compiler Options

These output-file options create or rename output files. They affect all C or C++ source files specified in the CL environment variable, on the command line, or in any command file. They include:

  • /Fd (Name the Program Database and Incremental Compilation State File)

  • /FD (Generate File Dependencies)

  • /Fe (Name the Executable File)

  • /Fm (Generate a Map File)

  • /Fo (Name the Object File)

  • /Fp (Name or Use a Precompiled Header File)

Other output-file options are available in the Listing Files category on the C/C++ tab of the Project Settings dialog box. They include:

  • Generate Browse Info (/FR)

  • Exclude Local Variables (/Fr)

  • Intermediate Browse Info File Destination (/FR[filename] or /Fr[filename])

  • Listing File Type (/FA[c|s])

  • Listing File Name(/Fa[filename ])


Drive, Path, and File Specifications

Home | Overview | How Do I | Compiler Options

Each output-file option accepts a filename argument, with which you can specify a location and a name for the output file. The argument can include a drive name, a path specification, and/or a file name. No space is allowed between the option and the argument.

If filename is a path without a file name (that is, a directory), end the path with a backslash (\) to differentiate it from a file name. If a file name is specified without an extension, the output file is given a default extension. If no argument is specified, the output file is given the base name of the source file and an extension determined by the type of output file.


Device Names for Windows

Home | Overview | How Do I | Compiler Options

You can append the device names AUX, CON, PRN, and NUL to the output-file options to direct the output file to the named device. No space is allowed between the option and the device name. Do not append a colon (:) to the device name. The device names and their behavior are shown in the following table.

Device name | Result
AUX | The listing file is sent to an auxiliary device.
CON | The listing file is sent to the console.
PRN | The listing file is sent to a printer.
NUL | No file is created.

Example

In the following example, appending PRN to /Fm sends a map file to the printer:

CL /FmPRN HELLO.CPP


/FA, /Fa (Listing File)

Home | Overview | How Do I | Compiler Options

This option creates a listing file. The listing file always contains assembly code. The optional arguments control the generation of source code and machine code and the extension of the listing file as follows:

Command Line | Project Settings | Listing Contents; Filename Extension
/FA | Assembly-Only Listing | Assembly code; .ASM
/FAc | Assembly With Machine Code | Machine and assembly code; .COD
/FAs | Assembly With Source Code | Source and assembly code; .ASM
/FAcs | Assembly, Machine Code, and Source | Machine, source, and assembly code; .COD
/Fafilename | Listing File Name | Use /Fa to specify a directory and/or filename for the selected type of listing file. By default, the base name of the listing file is the base name of the source file.

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Listing Files in the Category box. See the Listing File Type drop-down box.

Example

In the following example, CL produces a combined source and machine-code listing called HELLO.COD.

CL /FAcs HELLO.CPP


/Fd (Name PDB File)

Home | Overview | How Do I | Compiler Options

The /Fdfilename option specifies a file name for a program database (PDB) other than the default name, VC50.PDB, created by /Zi. No space is allowed between /Fd and filename. If you do not specify an extension to filename, the extension .PDB is used. If filename ends in a backslash (to specify the name of a directory), the default file name, VC50.PDB, is used. For information on PDBs, see /Z7, /Zd, /Zi (Debug Info).

Note This option also names the compiler's state or .IDB file (used by minimal rebuild and incremental compilation).

Example

The following command creates a .PDB file called PROG.PDB that contains debugging information and an .IDB file called PROG.IDB that contains incremental compilation and minimal rebuild information.

CL /DDEBUG /Zi /FdPROG.PDB PROG.CPP


/FD (Generate File Dependencies)

Home | Overview | How Do I | Compiler Options

The development environment's build system uses the /FD option to ensure that the most reliable dependency information is used when it builds your project.


/Fe (Name EXE File)

Home | Overview | How Do I | Compiler Options

The /Fefilename option names an .EXE file or DLL or creates it in a different directory. No space is allowed between /Fe and filename. By default, CL names the file with the base name of the first file (source or object) on the command line plus the extension .EXE (or .DLL if you use the /LD option to create a dynamic-link library).

If you specify the /c option to suppress linking, /Fe has no effect.

Examples

The following example compiles and links all C source files in the current directory. The resulting executable file is named PROCESS.EXE and is created in the directory C:\BIN.

CL /FeC:\BIN\PROCESS *.C

The following example is similar to the first example, except that the executable file is given the same base name as the first file compiled instead of being named PROCESS.EXE. The .EXE file is created in the directory C:\BIN.

CL /FeC:\BIN\ *.C


/FI (Name Forced Include File)

Home | Overview | How Do I | Compiler Options

The /FIfilename option causes the preprocessor to process the header file specified by filename. Each filename is included as if it were specified with double quotation marks (") in an #include directive on line 0 of every C or C++ source file specified in the CL environment variable, on the command line, or in any command file. If multiple /FI options are used, the files are included in the order they are processed by CL. The space between /FI and filename is optional.


/Fm (Name Map File)

Home | Overview | How Do I | Compiler Options

The /Fm[filename] option instructs the linker to produce a map file. No space is allowed between /Fm and filename. The map file contains a list of segments in the order of their appearance within the corresponding .EXE file or DLL. By default, the map file is given the base name of the corresponding C or C++ source file with a .MAP extension. If you specify the /c option to suppress linking, /Fm has no effect.

Global symbols in a map file usually have one or more leading underscores, because the compiler adds an underscore to the beginning of variable names. Many of the global symbols that appear in the map file are used internally by the compiler and the standard libraries.

For more information on map files, see the /MAP linker option.


/Fo (Name Object File)

Home | Overview | How Do I | Compiler Options

The /Fofilename option names an .OBJ file or creates it in a different directory. No space is allowed between /Fo and filename. By default, CL names the object file with the base name of the source file plus the extension .OBJ. You can give any name and extension you want for filename. However, it is recommended that you use the conventional .OBJ extension.

Example

The following command line compiles the source file THIS.C and gives the resulting object file the name THIS.OBJ by default. The directory specification B:\OBJECT\ tells CL to create THIS.OBJ in an existing directory named \OBJECT on drive B.

CL /FoB:\OBJECT\ THIS.C


/Fp (Name .PCH File)

Home | Overview | How Do I | Compiler Options

Use the /Fpfilename option with the /YX, /Yc, and /Yu options to provide a name for a precompiled header (.PCH) file (and path) that is different from the default. You can also use /Fp to specify the use of a .PCH file that is different from the filename argument to the /Yc option or the base name of the source file.

No space is allowed between /Fp and filename. If you do not specify an extension to filename, an extension of .PCH is assumed. If filename ends in a backslash (to specify the name of a directory), the default filename VC50.PCH is appended to filename.

Examples

The following command renames the default VC50.PCH file created and used by /YX:

CL /YX /FpMYPCH.PCH PROG.CPP

The following command creates a precompiled header file DPROG.PCH for a debugging version of a program:

CL /DDEBUG /Zi /Yc /FpDPROG.PCH PROG.CPP

The following command specifies the use of a precompiled header file named MYPCH.PCH. The compiler assumes that the source code in PROG.CPP has been precompiled through MYAPP.H, and that the precompiled code resides in MYPCH.PCH. It uses the content of MYPCH.PCH and compiles the rest of PROG.CPP to create an .OBJ file. Because none of these options suppresses the linker, the output of this example is a file named PROG.EXE.

CL /YuMYAPP.H /FpMYPCH.PCH PROG.CPP


/FR, /Fr (Create .SBR File)

Home | Overview | How Do I | Compiler Options

These options create an .SBR file containing symbolic information. During the build process, the Microsoft Browse Information File Maintenance Utility (BSCMAKE) uses the .SBR files to create a .BSC file that you can examine in browse windows.

Command Line | Project Settings | Description
/FR[filename] | Generate Browse Info | Creates an .SBR file with complete symbolic information
/Fr[filename] | Exclude Local Variables from Browse Info | Creates an .SBR file without information on local variables

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Listing Files in the Category box.

By default, the output file has the source file’s base name and an .SBR extension. On the command line, use filename to specify a name and directory other than the default. (No space is allowed before the file name argument.) Or in the Project Settings dialog box, use the Intermediate Browse Info File Destination text box. An .SBR extension is required.

The /Zn option suppresses packing of the .SBR file.


/G (Optimize for Processor) Options

Home | Overview | How Do I | Compiler Options

The Processor options direct the compiler to optimize code generation for the 80386, 80486, or Pentium® processors.

Command Line | Project Settings | Description
/GB | Blend | Optimizes the code created to favor the Pentium. It blends the optimizations for the 80386 (/G3), 80486 (/G4), Pentium (/G5), and Pentium Pro (/G6) options. This option forces a value of 500 for the _M_IX86 preprocessor macro. This value is the default. Future versions of the compiler will issue a different value to reflect the dominant processor.
/G6 | Pentium Pro | Optimizes the code created to favor the Pentium Pro. Use this option for programs meant only for the Pentium Pro. This option forces a value of 600 for the _M_IX86 preprocessor macro.
/G5 | Pentium | Optimizes the code created to favor the Pentium. Use this option for programs meant only for the Pentium. This option forces a value of 500 for the _M_IX86 preprocessor macro.
/G3 | 80386 | Phased out for Visual C++ 5.0. Forces a value of 300 for the _M_IX86 preprocessor macro. The compiler ignores this option.
/G4 | 80486 | Phased out in Visual C++ 5.0. Forces a value of 400 for the _M_IX86 preprocessor macro. The compiler ignores this option.

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box. Click the Processor drop-down list.


/GA (Optimize for Windows Application)

Home | Overview | How Do I | Compiler Options

The /GA option speeds up the access of data declared with the __declspec(thread) attribute in a Windows program. When this optimization switch is set, the __tls_index macro is assumed to be 0.


/GD (Optimize for Windows DLL)

Home | Overview | How Do I | Compiler Options

This optimization option is for future use.


/Gd, /Gr, /Gz (Calling Convention)

Home | Overview | How Do I | Compiler Options

The calling convention options determine the order in which arguments passed to functions are pushed onto the stack; which function, calling or called, removes the arguments from the stack; and the name-decorating convention that the compiler uses to identify individual functions. (To find the Calling Convention options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box.)

Command Line | Project Settings | Description
/Gd | __cdecl | Specifies the C calling convention for all functions that are not C++ member functions or are not marked as __stdcall or __fastcall. This is the default setting.
/Gr | __fastcall | Specifies the __fastcall calling convention for all functions that are not C++ member functions or are not marked as __cdecl or __stdcall. All __fastcall functions must have prototypes.
/Gz | __stdcall | Specifies the __stdcall calling convention for all prototyped C functions that do not take a variable number of arguments and are not marked as __cdecl or __fastcall. All __stdcall functions must have prototypes.

Note x86 Specific —>By default, C++ member functions use a calling convention in cases where the member function’s this pointer is passed in the ECX register. All other arguments are pushed onto the stack from right to left, and the called routine pops the member function’s arguments from the stack. END x86 Specific A member function that is explicitly marked as __cdecl, __fastcall, or __stdcall uses the specified calling convention. A member function that takes a variable number of arguments always uses the __cdecl calling convention.

__cdecl Specifics

For C, the __cdecl naming convention uses the function name preceded by an underscore ( _ ); no case translation is performed. Unless declared as extern "C", C++ functions use a different name-decorating scheme. For more information on decorated names, see Decorated Names.

__fastcall Specifics

Some of a __fastcall function’s arguments are passed in registers x86 Specific —> ECX and EDX END x86 Specific, and the rest are pushed onto the stack from right to left. The called routine pops these arguments from the stack before it returns. Typically, /Gr decreases execution time.

Important Be careful when using the __fastcall calling convention for any function written in inline assembly language. Your use of registers could conflict with the compiler’s use.

For C, the __fastcall naming convention uses the function name preceded by an at sign (@) followed by the size of the function’s arguments in bytes. No case translation is done. The compiler uses the following template for the naming convention:

@function_name@number

Note Microsoft does not guarantee the same implementation of the __fastcall calling convention between compiler releases. For example, the implementation differs between the 16-bit and 32-bit compilers.

When using the __fastcall naming convention, use the standard include files. Otherwise, you will get unresolved external references.

__stdcall Specifics

A __stdcall function’s arguments are pushed onto the stack from right to left, and the called function pops these arguments from the stack before it returns.

For C, the __stdcall naming convention uses the function name preceded by an underscore ( _ ) and followed by an at sign (@) and the size of the function’s arguments in bytes. No case translation is performed. The compiler uses the following template for the naming convention:

_functionname@number

x86 Specific —>This option has no effect on the name decoration of C++ methods and functions. Unless declared as extern "C", C++ methods and functions use a different name-decorating scheme. For more information on decorated names, see Decorated Names. END x86 Specific


/Ge (Enable Stack Probes)

Home | Overview | How Do I | Compiler Options

This option (and the /Gs option with a size of 0) activates stack probes for every function call that requires storage for local variables. This mechanism is useful only if you rewrite the functionality of the stack probe. It is recommended that you use the /Gh option rather than rewriting the stack probe.


/Gf, /GF (Eliminate Duplicate Strings)

Home | Overview | How Do I | Compiler Options

This option enables the compiler to place a single copy of identical strings into the .EXE file. Because identical strings are copied into a single memory location, programs compiled with this option can be smaller than those compiled without it. This space optimization is also called “string pooling.” Using this option ensures that string pooling occurs in most cases.

Command Line | Project Settings | Description
/Gf | Eliminate Duplicate Strings | Pools strings
/GF | Not applicable | Pools strings and places them in read-only memory

To find the Eliminate Duplicate Strings option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Customize in the Category box.

The /GF option enables the compiler to pool strings and place them in read-only memory. By placing the strings in read-only memory, the operating system does not need to swap that portion of memory. Instead, it can read the strings back from the image file. Strings placed in read-only memory cannot be modified; if you try to modify them, you will see an Application Error dialog box.

The /GF option is comparable to the /Gf option, except that /Gf does not place the strings in read-only memory. When you are using the /Gf option, your program must not write over pooled strings. Also, if you use identical strings to allocate string buffers, the /Gf option pools the strings. Thus, what was intended as multiple pointers to multiple buffers ends up as multiple pointers to a single buffer. For example, with /Gf, the following code causes s and t to point to the same memory because they are initialized with the same string:

char *s = "This is a character buffer";
char *t = "This is a character buffer";


/Gh (Enable Hook Function Call)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This option calls __penter at the start of every method or function. The __penter function is not part of any library. This call is a hook for your use. Use assembly language to write the function.

Unless you plan to explicitly call __penter, you do not need to provide a prototype. The function must appear as if it had the following prototype, and it must push the content of all registers on entry and pop the unchanged content on exit:

void __cdecl __penter( void );


/Gi (Enable Incremental Compilation)

Home | Overview | How Do I | Compiler Options

The Enable Incremental Compilation (/Gi) option controls the incremental compiler, which compiles only those functions that have changed since the last compile. The compiler saves state information from the first compile in the project’s .IDB file (the default name is project.IDB or VC50.IDB for files compiled without a project). The compiler uses this state information to speed subsequent compiles.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Customize in the Category box.

The following options prevent incremental compilation:

  • /Gi– (Disable Incremental Compilation)

  • /Z7 (Place Debug Information in Object Modules)

  • /FA (Generate a Listing File)

  • /Zg (Generate Function Prototypes)

  • /E, /EP, or /P (Preprocess the File)

If the compiler cannot find the project’s .PDB file or .IDB file (or either is read-only), it cannot incrementally compile.

Note Object (.OBJ) files created with the Enable Incremental Compilation option are larger than those with incremental compilation disabled because of padding. Padding allows the compiler to add to the .OBJ file without recreating it. Because these .OBJ files are larger, you should disable incremental compilation when building a version of your program for release.


/Gm (Enable Minimal Rebuild)

Home | Overview | How Do I | Compiler Options

The Enable Minimal Rebuild (/Gm) option controls minimal rebuild, which determines whether C++ source files that include changed C++ class definitions (stored in header (.H) files) need to be recompiled. The compiler stores dependency information between source files and class definitions in the project's .IDB file during the first compile. (Dependency information tells which source file is dependent on which class definition, and which .H file the definition is located in.) Subsequent compiles use the information stored in the .IDB file to determine whether a source file needs to be compiled, even if it includes a modified .H file.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Customize in the Category box.

Note Minimal rebuild relies on class definitions not changing between include files. Class definitions must be global for a project (there should be only one definition of a given class), because the dependency information in the .IDB file is created for the entire project. If you have more than one definition for a class in your project, disable minimal rebuild.


/GR (Enable Run-Time Type Information)

Home | Overview | How Do I | Compiler Options

The Enable Run-Time Type Information option (/GR) causes the compiler to add code to check object types at run time. When this option is specified, the compiler defines the _CPPRTTI preprocessor macro. The option is cleared (/GR–) by default.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click C++ Language in the Category box.

For more information on run-time type checking, see Run-Time Type Information in the C++ Language Reference.


/Gs (Control Stack Checking Calls)

Home | Overview | How Do I | Compiler Options

The /Gssize option is an advanced feature with which you can control stack probes. A stack probe is a sequence of code that the compiler inserts into every function call. When activated, a stack probe reaches benignly into memory by the amount of space required to store the associated function’s local variables.

If a function requires more than size stack space for local variables, its stack probe is activated. The default value of size is the size of one page (4K for 80x86 processors). This value allows a carefully tuned interaction between an application for Win32 and the Windows NT virtual-memory manager to increase the amount of memory committed to the program stack at run time.

Warning The default value of size is carefully chosen to allow the program stack of applications for Win32 to grow at run time. Do not change the default setting of /Gs unless you know exactly why you need to change it.

Some programs, such as virtual device drivers, do not require this default stack-growth mechanism. In such cases, the stack probes are not necessary. You can stop the compiler from generating stack probes by setting size to a value that is larger than any function will require for local variable storage. No space is allowed between /Gs and size.

The /Gs option with a size of 0 has the same result as the /Ge option.

You can turn stack probes on or off by using #pragma check_stack. Note that the /Gs option and the check_stack pragma have no effect on standard C library routines; they affect only the functions you compile.


/GT (Support Fiber-Safe Thread-Local Storage)

Home | Overview | How Do I | Compiler Options

The /GT option supports fiber safety for data allocated using static thread-local storage, that is, data allocated with __declspec( thread ).

A fiber is a lightweight object that consists of a stack and a register context and can be scheduled on various threads. A fiber can run on any thread. Because a fiber may get swapped out and restarted later on a different thread, it must not be cached or optimized as a common subexpression across a function call (see the /Og option for details). The /GT switch prevents such optimizations.


/GX (Enable Exception Handling)

Home | Overview | How Do I | Compiler Options

This option enables synchronous exception handling with the assumption that extern C functions never throw an exception. It is now equivalent to /EHsc.

For more information, see Exception Handling Topics (C++).


/Gy (Enable Function-Level Linking)

Home | Overview | How Do I | Compiler Options

This option allows the compiler to package individual functions in the form of packaged functions (COMDATs). The linker requires that functions be packaged separately as COMDATs to exclude or order individual functions in a DLL or .EXE file. (To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Customize in the Category box.)

You can use the linker’s /OPT:REF option to exclude unreferenced packaged functions from the .EXE file. For more information, see /OPT:REF. You can use the linker’s /ORDER option to place packaged functions in a specified order in the .EXE file. For more information, see /ORDER.

Inline functions are always packaged if they are instantiated as calls (for example, if inlining is turned off, or you take a function address). In addition, C++ member functions defined within the class declaration are automatically packaged; other functions are not, and selecting this option is required to compile them as packaged functions.


/GZ (Catch Release-Build Errors in Debug Build)

Home | Overview | How Do I | Compiler Options

Some bugs normally arise only when you switch to a Release build (/O1, /O2, /Ox, or /Og). You can use the /GZ option to enable run-time checks to catch these bugs in a Debug (/Od) build. /GZ is not compatible with /O1, /O2, /Ox, or /Og builds.

Note: Use of the /GZ option will disable any #pragma optimize statements in your code.

The /GZ option does the following:

  • Auto-initialization of local variables

  • Function pointer call stack validation

  • Call stack validation

See Creating a Release Build: Overview for more information on going from Debug builds to Release builds.

Auto-initialization of Local Variables

/GZ initializes all local variables not explicitly initialized by the program. It fills all memory used by these variables with 0xCC.

Assuming the stack is zero, code with uninitialized variables may fail with /GZ. Consider the following example. When compiled with /Od or /Ox without /GZ, this code may produce an access-violation exception, or it may appear to run correctly. When compiled with /Gz /Od, it always produces the exception. You can catch the exception in the debugger and get some hints about the exact location of failure.

#include <stdio.h>

void function1(char **pptr)
{
   printf("*pptr = 0x%X\n", *pptr);
   if(*pptr == NULL)
      *pptr = "Hello world\n";
}
void function2()
{
   int padding[10];          // force sub esp frame initialization
   char * p;               // p is uninitialized

   function1(&p);
   puts(p);
}

void main()
{
   int padding[1000];        // Force clean stack page
   function2();
}

Function Pointer Call Stack Validation

The stack pointer (ESP) is checked to make sure it is the same before and after the call through the function pointer. This can catch any mismatch between the calling function’s cleanup (__cdecl) calling convention and called function’s cleanup calling conventions (__sdtcall, __fastcall, __thiscall) when calling through a function pointer.

This example works with /Od, fails with /Ox and raises an exception with /GZ. You get an exception breakpoint pop-up if compiled with a release version of the run-time library and a more meaningful message when compiled with the debug version of the run-time library.

void __stdcall function1(char *p)
{
   puts(p);
}

typedef void (*PFUNC)(char *);

main()
{
   PFUNC pfunction1 = (PFUNC)function1;

   pfunction1("Hello world\n");
}

A more realistic scenario occurs with GetProcAddress:

#include <windows.h>
void function1()
{
   typedef int (*FPTYPE)(int); // should be "int(__stdcall *)(int)"
   FPTYPE fp;
   int ret = 0;
   HINSTANCE hinst = LoadLibrary( "your.dll" );
   fp = (FPTYPE) GetProcAddress( hinst, "SomeFunc");

   ret = (*fp)(22);      // ESP invalid after this call.
                        // but it is caught upon return

   FreeLibrary( hinst );

   // and also caught at function exit
}

Function pointer call stack validation will also catch cases where a function prototype has the incorrect number of parameters if the function uses the __stdcall, __fastcall, or __thiscall calling convention. __cdecl cases are not caught because the caller does both the pushes and the pops of parameters.

Call Stack Validation

The stack pointer (ESP) is checked at the end of the function to see that the stack pointer has not been changed. This can catch cases where ESP is corrupted in inline assembly or a non-pointer function's calling convention is declared incorrectly.


/H (Restrict Length of External Names)

Home | Overview | How Do I | Compiler Options

The /Hnumber option restricts the length of external (public) names. The program can contain external names longer than number characters, but the extra characters are ignored. A space between /H and number is optional. The compiler imposes no limit on the length of external identifiers.

The limit on length includes any compiler-created leading underscore (_) or at sign (@). The compiler adds a leading underscore (_) to names modified by the __cdecl (default) and __stdcall calling conventions, and a leading at sign (@) to names modified by the __fastcall calling convention. It appends argument size information to names modified by the __fastcall and __stdcall calling conventions, and adds type information to C++ names.

You may find the /H option useful when creating mixed-language or portable programs, or when using tools that impose limits on the length of external identifiers.


/HELP (Compiler Command-Line Help)

Home | Overview | How Do I | Compiler Options

Syntax

/HELP
/help
/?

This option displays a listing of compiler options to standard output.


/I (Additional Include Directories)

Home | Overview | How Do I | Compiler Options

The Additional Include Directories option (/Idirectory) adds one or more directories to the list of directories searched for include files. Directories are searched only until the specified include file is found. You can use this option with the Ignore Standard Include Paths (/X) option.

In the Project Settings dialog box, use a comma to separate directories to be searched when entering more than one directory. (To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Preprocessor in the Category box.)

On the command line, a space between /I and directory is optional. To search more than one directory, type one /I option for each directory.

The compiler searches for directories in the following order:

  4. Directories containing the source file.

  5. Directories specified with the /I option, in the order that CL encounters them.

  6. Directories specified in the INCLUDE environment variable.

Example

The following command looks for the include files requested by MAIN.C in the following order: first in the directory containing MAIN.C, then in the \INCLUDE directory, then in the \MY\INCLUDE directory, and finally in the directories assigned to the INCLUDE environment variable.

CL /I \INCLUDE /I\MY\INCLUDE MAIN.C


/J (Default char Type is unsigned)

Home | Overview | How Do I | Compiler Options

This option changes the default char type from signed char to unsigned char, and the char type is zero-extended when widened to an int type. If a char value is explicitly declared signed, the /J option does not affect it, and the value is sign-extended when widened to an int type.

The /J option defines _CHAR_UNSIGNED, which is used with #ifndef in the LIMITS.H file to define the range of the default char type.

Neither ANSI C nor C++ requires a specific implementation of the char type. This option is useful when you are working with character data that will eventually be translated into a language other than English.


/link (Pass Options to Linker)

Home | Overview | How Do I | Compiler Options

The /link option option passes one or more linker options to LINK. The /link option and its linker options must appear after any file names and CL options. A space is required between /link and option. See Set Linker Options for a complete list.


/MD, /ML, /MT, /LD (Use Run-Time Library)

Home | Overview | How Do I | Compiler Options

With these options, you can select either single-threaded or multithreaded run-time routines, indicate that a multithreaded module is a dynamic-link library (DLL), and select the retail or debug version of the library.

Note Having more than one copy of the run-time libraries in a process can cause problems, because static data in one copy is not shared with the other copy. To ensure that your process contains only one copy, avoid mixing static and dynamic versions of the run-time libraries. The linker will prevent you from linking with both static and dynamic versions within one .EXE file, but you can still end up with two (or more) copies of the run-time libraries. For example, a dynamic-link library linked with the static (non-DLL) versions of the run-time libraries can cause problems when used with an .EXE file that was linked with the dynamic (DLL) version of the run-time libraries. (You should also avoid mixing the debug and non-debug versions of the libraries in one process.)

Command Line | Project Settings | Description
/MD | Multithreaded DLL | Defines _MT and _DLL so that both multithread- and DLL-specific versions of the run-time routines are selected from the standard .H files. This option also causes the compiler to place the library name MSVCRT.LIB into the .OBJ file. Applications compiled with this option are statically linked to MSVCRT.LIB. This library provides a layer of code that allows the linker to resolve external references. The actual working code is contained in MSVCRT.DLL, which must be available at run time to applications linked with MSVCRT.LIB.
/MDd | Debug Multithreaded DLL | Defines _DEBUG, _MT, and _DLL so that debug multithread- and DLL-specific versions of the run-time routines are selected from the standard .H files. It also causes the compiler to place the library name MSVCRTD.LIB into the .OBJ file.
/ML | Single-Threaded | Causes the compiler to place the library name LIBC.LIB into the .OBJ file so that the linker will use LIBC.LIB to resolve external symbols. This is the compiler’s default action. LIBC.LIB does not provide multithread support.
/MLd | Debug Single-Threaded | Defines _DEBUG and causes the compiler to place the library name LIBCD.LIB into the .OBJ file so that the linker will use LIBCD.LIB to resolve external symbols. LIBCD.LIB does not provide multithread support.
/MT | Multithreaded | Defines _MT so that multithread-specific versions of the run-time routines are selected from the standard header (.H) files. This option also causes the compiler to place the library name LIBCMT.LIB into the .OBJ file so that the linker will use LIBCMT.LIB to resolve external symbols. Either /MT or /MD (or their debug equivalents /MTd or /MDd) is required to create multithreaded programs.
/MTd | Debug Multithreaded | Defines _DEBUG and _MT. Defining _MT causes multithread-specific versions of the run-time routines to be selected from the standard .H files. This option also causes the compiler to place the library name LIBCMTD.LIB into the .OBJ file so that the linker will use LIBCMTD.LIB to resolve external symbols. Either /MTd or /MDd (or their non-debug equivalents /MT or MD) is required to create multithreaded programs.
/LD | Not applicable | Creates a DLL. Passes the /DLL option to the linker. The linker looks for, but does not require, a DllMain function. If you do not write a DllMain function, the linker inserts a DllMain function that returns TRUE. Links the DLL startup code. Creates an import library (.LIB), if an export (.EXP) file is not specified on the command line; you link the import library to applications that call your DLL. Interprets /Fe as naming a DLL rather than an .EXE file; the default program name becomes basename.DLL instead of basename.EXE. Changes default run-time library support to /MT if you have not explicitly specified one of the /M options
/LDd | Not applicable | Creates a debug DLL. Defines _DEBUG.

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box. See the Use Run-Time Library drop-down box.

The debug options select the debug versions of the library or DLL and define _DEBUG. For more information on using the debug versions, see C Run-Time Debug Libraries.

For further discussion of DLLs, see DLL Topics.


/nologo (Suppress Startup Banner and Information Messages)

Home | Overview | How Do I | Compiler Options

This option suppresses display of the sign-on banner (when the compiler starts up) and informational messages (during compiling).

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Customize in the Category box.


/O options (Optimize Code)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Optimizations (/O) options determine how the compiler fine-tunes the performance of your program. Four of the five optimization categories (Default, Disable (Debug), Maximize Speed, and Minimize Size) in the Optimizations drop-down list box require no further optimization on your part. If you select the fifth optimization category, Customize, you can set specific optimizations using the selections in the Optimizations list box.

Use /Od to disable optimization, speed compilation, and simplify debugging. Use /Og to enable fundamental global optimizations.

The following table summarizes the optimizations. Click a command name for more detail.

Command Line | Project Settings | Description
/O1 | Minimize Size | Creates the smallest code in the majority of cases.
/O2 | Maximize Speed | Creates the fastest code in the majority of cases.
/Oa | Assume No Aliasing | Tells the compiler that your program does not use aliasing. An alias is a name that refers to a memory location that is already referred to by a different name. Using this option allows the compiler to apply optimizations it couldn’t otherwise use, such as storing variables in registers and performing loop optimizations.
/Ow | Assume Aliasing Across Function Calls | Tells the compiler that no aliasing occurs within function bodies but might occur across function calls. After each function call, pointer variables must be reloaded from memory.
/Ob | Inline Function Expansion | Controls which functions become expanded. Expanding a function inline makes the program faster because it does not incur the overhead of calling the function.
/Og | Global Optimizations | Provides local and global optimizations, automatic-register allocation, and loop optimization.
/Od | Disable (Debug) | Turns off all optimizations in the program and speeds compilation. This option simplifies debugging because it suppresses code movement.
/Oi | Generate Intrinsic Functions | Replaces some function calls with intrinsic or otherwise special forms of the function that help your application run faster. Programs that use intrinsic functions are faster because they do not have the overhead of function calls, but may be larger because of the additional code created.
/Op | Improve Float Consistency | Improves the consistency of floating-point tests for equality and inequality by disabling optimizations that could change the precision of floating-point calculations.
/Os | Favor Small Code | Minimizes the size of .EXE files or DLLs by instructing the compiler to favor size over speed. The compiler can reduce many C and C++ constructs to functionally similar sequences of machine code. Occasionally these differences offer trade-offs of size versus speed. If you do not select this option, code may be larger and may be faster.
/Ot | Favor Fast Code; Default | Maximizes the speed of .EXE files and DLLs by instructing the compiler to favor speed over size. The compiler can reduce many C and C++ constructs to functionally similar sequences of machine code. Occasionally these differences offer trade-offs of size versus speed.
/Ox | Full Optimization | Combines optimizing options to produce the fastest possible program.
/Oy | Frame-Pointer Omission | Suppresses creation of frame pointers on the call stack. This option speeds function calls, because no frame pointers need to be set up and removed. It also frees one more register, x86 Specific —>EBP on the Intel 386 (or later), END x86 Specific for storing frequently used variables and subexpressions.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box.


/O1, /O2 (Minimize Size, Maximize Speed)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

These options select a predefined set of options that affect the size and speed of files as follows:

Option | Equivalent to | Comment
/O1 (Minimize Size) | /Og /Os /Oy /Ob1 /Gs /Gf /Gy | Creates the smallest code in the majority of cases.
/O2 (Maximize Speed) | /Og /Oi /Ot /Oy /Ob1 /Gs /Gf /Gy | Creates the fastest code in the majority of cases. (Default setting for release builds)

x86 Specific —>

You can use other options to improve the size or speed of many applications. For example, this option doesn’t use the /G5 option to produce code that is optimized for computers based on the Pentium processor.

These options imply the use of the Frame-Pointer Omission (/Oy) option.

END x86 Specific

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Maximize Speed or Minimize Size.


/Oa, /Ow (Assume No Aliasing, Assume Aliasing Across Function Calls)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Aliasing can slow your application by reducing both register storage of variables and loop optimizations.

The Assume No Aliasing (/Oa) option tells the compiler that your program does not use aliasing. An alias is a name that refers to a memory location that is already referred to by a different name.

The Assume Aliasing Across Function Calls (/Ow) option tells the compiler that no aliasing occurs within function bodies but might occur across function calls. After each function call, pointer variables must be reloaded from memory.

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Customize.

Rules for using /Oa and /Ow

The following rules must be followed for any variable not declared as volatile, or else /Oa and /Ow are ignored. In these rules, a variable is referenced if it is on either side of an assignment or if a function uses it in an argument:

  • No pointer references a variable that is used directly.

  • No variable is used directly if a pointer to the variable is being used.

  • No variable is used directly if the variable’s address is taken within a function.

  • No pointer is used to access a memory location if another pointer is used to modify the same memory location.

Aliasing bugs most frequently show up as corrupted data. If variables are assigned seemingly random values, compile the program with Disable (/Od). If the program works when compiled with the /Od option, do not use /Oa or /Ow.

The following code fragment could have an aliasing problem:

i = -100;
while( i < 0 )
{
    i += x + y;
    *p = i;
}

Without /Oa or /Ow, the compiler must assume that x or y could be modified by the assignment to *p and cannot assume that x + y is constant for each loop iteration. If you specify /Oa or /Ow, the compiler assumes that modifying *p cannot affect either x or y and x + y can be removed from the loop.

Note You can disable optimizations around code that uses aliasing (for individual functions) by using #pragma optimize with the a or w option.


/Ob (In-line Function Expansion)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The In-line Function Expansion (/Obn) options control inline expansion of functions, where n is one of the following:

Command Line | Project Settings | Description
/Ob0 | Disable | Disables inline expansion (default)
/Ob1 | Only __inline | Expands only functions marked as inline or __inline or, in a C++ member function, defined within a class declaration (default with /O1, /O2, and /Ox)
/Ob2 | Any Suitable | Expands functions marked as inline or __inline and any other function that the compiler chooses (expansion occurs at compiler discretion—often referred to as “auto-inlining”)

(To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box.)

The compiler treats the inline expansion options and keywords as suggestions. There is no guarantee that functions will be inlined. You cannot force the compiler to inline a particular function.

You can also use #pragma auto_inline to exclude functions from being considered as candidates for inline expansion. Also see #pragma intrinsic.


/Od (Disable (Debug))

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This option turns off all optimizations in the program and speeds compilation. this option is the default. Because /Od suppresses code movement, it simplifies the debugging process. For information on the compile-for-debugging options, see /Zi, /Z7, and /Zd.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Disable (Debug).


/Og (Global Optimizations)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This option provides local and global optimizations, automatic-register allocation, and loop optimization. (To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Global Optimizations.)

  • Local and global common subexpression elimination

    In this optimization, the value of a common subexpression is calculated once. In the following example, if the values of b and c do not change between the three expressions, the compiler can assign the calculation of b + c to a temporary variable, and substitute the variable for b + c:

    a = b + c;
d = b + c;
e = b + c;

    For local common subexpression optimization, the compiler examines short sections of code for common subexpressions. For global common subexpression optimization, the compiler searches entire functions for common subexpressions.

  • Automatic register allocation

    This optimization allows the compiler to store frequently used variables and subexpressions in registers; the register keyword is ignored.

  • Loop optimization

    This optimization removes invariant subexpressions from the body of a loop. An optimal loop contains only expressions whose values change through each execution of the loop. In the following example, the expression x + y does not change in the loop body:

    i = -100;
while( i < 0 )
{
    i += x + y;
}

    After optimization, x + y is calculated once rather than every time the loop is executed:

    i = -100;
t = x + y;
while( i < 0 )
{
    i += t;
}

    Loop optimization is much more effective when the compiler can assume no aliasing, which you set with Assume No Aliasing (/Oa) or Assume Aliasing Across Function Calls (/Ow).

Note You can enable or disable global optimization on a function-by-function basis using the optimize pragma with the g option.

For related information, see Generate Intrinsic Functions (/Oi), Improve Float Consistency (/Op), and Full Optimization (/Ox).


/Oi (Generate Intrinsic Functions)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This option replaces some function calls with intrinsic or otherwise special forms of the function that help your application run faster. Programs that use intrinsic functions are faster because they do not have the overhead of function calls, but may be larger because of the additional code created. See #pragma intrinsic for related information.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Customize.

x86 Specific

This option replaces the following function calls with their intrinsic (inline) forms:

_disable | _outp | abs | memset
_enable | _outpw | fabs | strcat
_inp | _rotl | labs | strcmp
_inpw | _rotr | memcp | strcpy
_lrotl | _strset | memcpy | strlen
_lrotr |  |  |

Note The _alloca and setjmp functions are always generated inline; this behavior is not affected by /Oi.

The floating-point functions listed below do not have true intrinsic forms. If you use the Generate Intrinsic Functions option, the listed functions are replaced with versions that pass arguments directly to the floating-point chip rather than pushing them onto the program stack:

acos | cosh | pow | tanh
asin | fmod | sinh |

The floating-point functions listed below have true intrinsic forms when you specify both /Oi and /Og (or any option that includes /Og: /Ox, /O1, and /O2):

atan | exp | sin
atan2 | log | sqrt
cos | log10 | tan

The intrinsic floating-point functions do not perform any special checks on input values and so work in restricted ranges of input, and have different exception handling and boundary conditions than the library routines with the same name. Using the true intrinsic forms implies loss of IEEE exception handling, and loss of _matherr and errno functionality; the latter implies loss of ANSI conformance. However, the intrinsic forms can considerably speed up floating-point intensive programs, and for many programs, the conformance issues are of little practical value.

You can use Improve Float Consistency (/Op) or Disable Language Extensions (/Za) to override generation of true intrinsic floating-point options. In this case, the functions are generated as library routines that pass arguments directly to the floating-point chip instead of pushing them onto the program stack.

END x86 Specific

You also use #pragma intrinsic to create intrinsic functions, or #pragma function to explicitly force a function call.


/Op (Improve Float Consistency)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Improve Float Consistency (/Op[–]) option improves the consistency of floating-point tests for equality and inequality by disabling optimizations that could change the precision of floating-point calculations. (To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Customize.)

By default, the compiler uses the coprocessor’s 80-bit registers to hold the intermediate results of floating-point calculations. This increases program speed and decreases program size. However, because the calculation involves floating-point data types that are represented in memory by less than 80 bits, carrying the extra bits of precision (80 bits minus the number of bits in a smaller floating-point type) through a lengthy calculation can produce inconsistent results.

With /Op, the compiler loads data from memory prior to each floating-point operation and, if assignment occurs, writes the results back to memory upon completion. Loading the data prior to each operation guarantees that the data does not retain any significance greater than the capacity of its type.

A program compiled with /Op may be slower and larger than one compiled without /Op.

Note The /Op option disables inline generation of floating-point functions. The standard run-time library routines are used instead. For more information, see the /Oi option.

If you select the Disable Language Extensions (/Za) option in order to compile for ANSI compatibility, the use of /Op is implied. The use of /Op improves the consistency of floating-point tests for equality and inequality. The nature of the improved consistency provides for strict ANSI conformance and is the only situation under which /Op is selected by default. The /Op– option is provided to override the default selection of /Op with /Za. Specify /Op– on the command line (or in the Common|Project|Source File Options text box) after /Za, to disable /Op.

See Also IEEE Floating-Point Representation and Microsoft Languages, Why Floating Point Numbers May Lose Precision


/Os (Favor Small Code)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This option minimizes the size of executable files and DLLs by instructing the compiler to favor size over speed. The compiler can reduce many C and C++ constructs to functionally similar sequences of machine code. Occasionally these differences offer tradeoffs of size versus speed. The /Os and /Ot (Favor Fast Code) options allow you to specify a preference for one over the other:

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Customize.

Note The /Os and /Ot options have their greatest effect when used with /Og (Global Optimizations).


/Ot (Favor Fast Code)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This option maximizes the speed of .EXE files and DLLs by instructing the compiler to favor speed over size. (This is the default.) The compiler can reduce many C and C++ constructs to functionally similar sequences of machine code. Occasionally these differences offer trade-offs of size versus speed.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Customize.

x86 Specific

The following example code demonstrates the difference between the Favor Small Cod (/Os) options and the Favor Fast Code (/Ot) option:

/* differ.c
  This program implements a multiplication operator
  Compile with /Os to implement multiply explicitly as multiply.
  Compile with /Ot to implement as a series of shift and LEA instructions.
 */
int differ(int x)
{
    return x * 71;
}

As shown in the fragment of machine code below, when DIFFER.C is compiled for size (/Os), the compiler implements the multiply expression in the return statement explicitly as a multiply to produce a short but slower sequence of code:

   mov    eax, DWORD PTR _x$[ebp]
   imul   eax, 71                  ; 00000047H

Alternatively, when DIFFER.C is compiled for speed (/Ot) the compiler implements the multiply expression in the return statement as a series of shift and LEA instructions to produce a fast but longer sequence of code:

   mov    eax, DWORD PTR _x$[ebp]
   mov    ecx, eax
   shl    eax, 3
   lea    eax, DWORD PTR [eax+eax*8]
   sub    eax, ecx

END x86 Specific

Note The /Ot option is implied by the Maximize Speed (/O2) option. The /O2 option combines several options to produce very fast code. The /Os and /Ot options have their greatest effect when used with Global Optimizations (/Og).


/Ox (Full Optimization)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This option combines optimizing options to produce the fastest possible program. The effect is the same as using the following options:

Command Line | Development Environment
/Ob1 | In-line Function Expansion
/Og | Global Optimizations
/Oi | Generate Intrinsic Functions
/Ot | Favor Fast Code
/Oy | Frame-Pointer Omission
/Gs | Control Stack Probes

Note The use of Full Optimization implies the use of the Frame Pointer Omission (/Oy) option.

To find the Full Optimization option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Customize.


/Oy (Frame-Pointer Omission)

Home | Overview | How Do I | Compiler Options

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The /Oy option suppresses creation of frame pointers on the call stack. This option speeds function calls, since no frame pointers need to be set up and removed. It also frees one more register, x86 Specific —>EBP on the Intel 386 or later, END x86 Specific for storing frequently used variables and subexpressions.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Optimizations in the Category box. Under Optimizations, click Customize.

x86 Specific —> If your code requires EBP-based addressing, you can specify the /Oy– option after the /Ox option or use #pragma optimize with the "y" and off arguments to gain maximum optimization with EBP-based addressing. The compiler detects most situations where EBP-based addressing is required (for instance, with the _alloca and setjmp functions and with structured exception handling). END x86 Specific

The /Ox (Full Optimization) and /O1 and /O2 (Fast Code) options imply /Oy. Specifying /Oy– in the Common|Project|Source File Options text box (or on the command line) after the /Ox, /O1, or /O2 option disables /Oy, whether it is explicit or implied.


/P (Preprocess to a File)

Home | Overview | How Do I | Compiler Options

This option writes preprocessor output to a file with the same base name as the source file, but with the .I extension. It adds #line directives to the output file at the beginning and end of each included file and around lines removed by preprocessor directives that specify conditional compilation. The preprocessed listing file is identical to the original source file, except that all preprocessor directives are carried out, and macro expansions are performed.

This option suppresses compilation; CL does not produce an .OBJ file, even if the /Fo option is specified. The /P option also suppresses production of the alternate output files created by the /FA, /Fa, or /Fm option.

The /P option is similar to the /E and /EP options. Using /EP with /P suppresses placement of #line directives in the output file.

The following table summarizes the actions of the /E, /EP, and /P options.

Option | Preprocessor output includes #line directives? | Output sent to
/E | Yes | stdout
/P | Yes | .i file
/EP | No | stdout
/E /EP | No | stdout
/P /EP | No | .i file


/QI0f

Home | Overview | How Do I | Compiler Options

Syntax

/QI0f
/QI0f–

As part of its regular Pentium® Processor Specification Update process, Intel has disclosed an erratum in the Pentium processor that in rare circumstances causes incorrect decoding of certain 0F instructions.

(Additional information can be obtained in the Pentium Processor Specification Update, available from Intel.) Microsoft has enhanced Visual C++ to optionally generate code that is immune to the erratum. If you observe this erratum or are concerned that your code may be susceptible, include the /QI0f option on the command line or in the Projects Options box on the C/C++ tab in the Project Settings dialog box.

Intel recommends the use of this option for all code.


/QIfdiv

Home | Overview | How Do I | Compiler Options

Syntax

/QIfdiv
/QIfdiv–

The /QIfdiv option offers a workaround for the Intel Pentium microprocessors with flawed FDIV, FPREM, FPTAN, and FPATAN instructions. Microsoft has implemented helper routines in the run-time library that perform more accurate FDIV and FPREM calculations than the flawed processors, and it has provided hooks so that you can write your own helper functions for the FPTAN and FPATAN instructions.

By default, the workaround is disabled (/QIfdiv–), and the code generator emits code that is unsafe on a flawed Pentium.

If the workaround is enabled (/QIfdiv), the code generator emits fatter, safe code that tests for the processor bug and calls run-time routines instead of using the native instructions of the processor to generate correct floating-point results.

For related information, see /Op. Also see Why Floating Point Numbers May Lose Precision.

Note that replacing your processor is another solution to the computation flaws. Contact Intel Corporation for more information.

Most people need not worry about this situation, either because they do not use floating-point at all, or because they do not need an extremely high degree of accuracy. Those who need to be concerned are urged to make sure they understand the issues rather than simply assume that the tools will "just work."

Performance testing of this workaround indicates a worst case penalty is approximately 10% on a Pentium without the flaw, 2x on a flawed Pentium; and the realistic penalty is <1% on a Pentium without the flaw, and 10% on a flawed Pentium. As always, the results may vary. That is, you may see no slowdown in a realistic program, or you may see 2x in a realistic program. If performance is an issue for you, measure it and see what your actual results are. See Performance Tuning for more information.

This fix has been tested extensively. However, as with all software, there is always a possibility that bugs remain. You should rigorously test your applications to ensure correctness.

Accuracy of floating-point operations is a complex subject. Even with an accurate set of “atomic” operations, such as +, -, *, /, a program can give unexpected results. The C/C++ standard does not in general guarantee a specific order of evaluation for expressions, nor does it guarantee that intermediate results will be forced to a particular precision, so two programs that are logically equivalent on the surface may yield different results.


/Qlf (Kernal-level debug info)

Home | Overview | How Do I | Compiler Options

Syntax

/Qlf

Generates additional debug information for kernal-level device drivers.


/Tc, /Tp, /TC, /TP (Specify Source File Type)

Home | Overview | How Do I | Compiler Options

Syntax

/Tcfilename
/Tpfilename
/TC
/TP

The /Tc option specifies that filename is a C source file, even if it doesn’t have a .C extension. The /Tp option specifies that filename is a C++ source file, even if it doesn’t have a .CPP or .CXX extension. A space between the option and filename is optional. Each option specifies one file; to specify additional files, repeat the option.

/TC and /TP are "global" variants of /Tc and /Tp. They specify to the compiler to treat all files named on the command line as C source files (/TC) or C++ source files (/TP), without regard to location on the command line in relation to the option. These global options can be overridden on a single file via /Tc or /Tp.

By default, CL assumes that files with the .C extension are C source files and files with the .CPP or the .CXX extension are C++ source files.

Examples

The following CL command line specifies that MAIN.C, TEST.PRG, and COLLATE.PRG are all C source files. CL will not recognize PRINT.PRG.

CL MAIN.C /TcTEST.PRG /TcCOLLATE.PRG PRINT.PRG

The following CL command line specifies that FOO1.C, FOO2.CXX, FOO3.HUH, and FOO4.O are compiled as C++ files, and FOO5.Z is compiled as a C file.

CL FOO1.C FOO2.CXX FOO3.HUH FOO4.O /Tc FOO5.Z /TP


/U, /u (Undefine Symbols)

Home | Overview | How Do I | Compiler Options

These options undefine previously defined symbols.

Command Line | Project Settings | Description
/Usymbol | Undefined Symbols | Undefines a previously defined symbol
/u | Undefine All Symbols | Turns off every previously defined symbol

Type the name of a previously defined macro in the text box to undefine it. (Or specify symbol on the command line. A space between /U and symbol is optional.) To undefine additional macros, type additional ones, using a space to separate each. (On the command line, simply repeat /Usymbol.)

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Preprocessor in the Category box.

Neither of these options can be used to undefine symbols created with the #define directive. Both options turn off the following Microsoft-specific macros:

Symbol | Function
_CHAR_UNSIGNED | Default char type is unsigned. Defined when /J is specified.
_CPPRTTI | Defined for code compiled with the /GR (Enable Run-Time Type Information) option.
_CPPUNWIND | Defined for code compiled with the /GX (Enable Exception Handling) option.
_DLL | Defined when /MD is specified.
_M_IX86 | 1Defined as 500 for Blend (/GB), 300 for 80386 (/G3), 400 for 80486 (/G4), 500 for Pentium (/G5), and 600 for Pentium Pro (/G6).
_MSC_VER | Defines the compiler version. Defined as 1200 for Microsoft Visual C++ version 6.0. Always defined.
_WIN32 | 2Defined for applications for WIN32. Always defined.
_MT | Defined when /MD or /MT is specified.

1 x86 specific

2 x86 specific


/V (Version Number)

Home | Overview | How Do I | Compiler Options

Syntax

/Vstring

This option embeds a text string in the .OBJ file. This string can label an .OBJ file with a version number or a copyright notice. Any space or tab characters must be enclosed in double quotation marks (") if they are a part of the string. A backslash (\) must precede any double quotation marks if they are a part of the string. A space between /V and string is optional.

You can also use #pragma comment with the compiler comment-type argument to place the name and version number of the compiler in the .OBJ file.


/vd (Disable Construction Displacements)

Home | Overview | How Do I | Compiler Options

These options apply only to C++ code that uses virtual bases:

Command Line | Project Settings | Description
/vd0 | Disable Construction Displacements (check box selected) | Suppresses the vtordisp constructor/destructor displacement member. Choose this option only if you are certain that all class constructors and destructors call virtual functions virtually.
/vd1 | (Check box cleared) | Enables the creation of hidden vtordisp constructor/destructor displacement members. This choice is the default.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click C++ Language in the Category box.

Visual C++ implements C++ construction displacement support in situations where virtual inheritance is used. Construction displacements solve the problem created when a virtual function, declared in a virtual base and overridden in a derived class, is called from a constructor during construction of a further derived class.

The problem is that the virtual function may be passed an incorrect this pointer as a result of discrepancies between the displacements to the virtual bases of a class and the displacements to its derived classes. The solution provides a single construction displacement adjustment, called a vtordisp field, for each virtual base of a class.

By default, vtordisp fields are introduced whenever the code defines user-defined constructors and destructors and also overrides virtual functions of virtual bases.

These options affect entire source files. Use #pragma vtordisp to suppress and then reenable vtordisp fields on a class-by-class basis.


/vmb, /vmg (Representation Method)

Home | Overview | How Do I | Compiler Options

These options select the method that the compiler uses to represent pointers to class members. You can also use #pragma pointers_to_members in your code to specify a pointer representation.

Command Line | Project Settings | Description
/vmb | Best-Case Always | Use this option if you always define a class before you declare a pointer to a member of the class.
/vmg | General-Purpose Always | Use this option if you need to declare a pointer to a member of a class before defining the class. This need can arise if you define members in two different classes that reference each other. For such mutually referencing classes, one class must be referenced before it is defined. You must then choose an inheritance model from the General Purpose Representation drop-down list box.

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click C++ Language in the Category box. See the choices under Representation Method.

If you define a class before declaring a pointer to a member of the class using the Best-Case Always option, the compiler knows the kind of inheritance used by the class when it encounters the declaration of the pointer. Thus, it can use the smallest possible representation of a pointer and create the smallest amount of code required to operate on the pointer for each kind of inheritance.

With the Best-Case Always option, the compiler issues an error if it encounters the pointer declaration before the class definition. In this case, you must either reorganize your code or use the General-Purpose Always (/vmg) option. You can also use the pointers_to_members pragma or define the class using the __single_inheritance, __multiple_inheritance, or __virtual_inheritance keyword. These keywords allow control of the code created on a per-class basis.

For the Best-Case Always option, the corresponding argument to #pragma pointers_to_members is best_case.

For information on the use of the __single_inheritance, __multiple_inheritance, and __virtual_inheritance keywords, see Inheritance Keywords in the Language Quick Reference.


/vmm, /vms, /vmv (General Purpose Representation)

Home | Overview | How Do I | Compiler Options

If you select General-Purpose Always (/vmg) as the representation method, you must also specify an option to indicate the inheritance model of the not-yet-encountered class definition. You can select one of the following three options.

Command Line Project Settings Description
/vmm Point to Single- and Multiple-Inheritance Classes
  • Specifies the most general representation of a pointer to a member of a class to be one that uses multiple inheritance.

  • This representation is larger than that required for single inheritance.

  • If the inheritance model of a class definition for which a pointer to a member is declared is virtual, the compiler generates an error.

  • The corresponding argument to #pragma pointers_to_members is multiple_inheritance.
/vms Point to Single-Inheritance Classes
  • Specifies the most general representation of a pointer to a member of a class to be one that uses either no inheritance or single inheritance.

  • This is the smallest possible representation of a pointer to a member of a class.

  • If the inheritance model of a class definition for which a pointer to a member is declared is multiple or virtual, the compiler generates an error.

  • The corresponding argument to #pragma pointers_to_members is single_inheritance.
/vmv Point to Any Class
  • Specifies the most general representation of a pointer to a member of a class to be one that uses virtual inheritance.

  • This option requires a larger pointer and additional code to interpret the pointer than the other options.

  • It never causes an error and is the default.

  • The corresponding argument to #pragma pointers_to_members is virtual_inheritance.

On the command line, use any of these options with /vmg.

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click C++ Language in the Category box. When you click an option under Representation Method, the General Purpose Representation list box will be enabled.

When you specify one of these inheritance-model options, that model is used for all pointers to member classes, regardless of their inheritance type or whether the pointer is declared before or after the class.

Therefore, if you always use single-inheritance classes, you can reduce code size by selecting Point To Single-Inheritance Classes from the General Purpose Representation drop-down list box; however, if you want to compile using the most general case (at the expense of the largest data representation), you can select Point To Any Class, which allows pointers to classes of all inheritance types. Point To Any Class is the default.


/W, /w (Warning Level)

Home | Overview | How Do I | Compiler Options

These options control the number of warning messages produced by the compiler. They affect only source files, not object (.OBJ) files.

Command Line | Project Settings | Description
/W0 or /w | None | Turns off all warning messages.
/W1 | Level 1 | Displays severe warning messages. This is the default.
/W2 | Level 2 | Displays a less-severe level of warning message than /W1.
/W3 | Level 3 | Displays less-severe warnings than /W2, such as warnings about function calls that precede their function prototypes. /W3 is the most sensitive warning level recommended for production pruposes.
/W4 | Level 4 | Displays informational warnings which in most cases can be safely ignored. /W4 should be used occasionally to provide “lint” level warnings and is not recommended as your usual warning level setting.
/WX | Warnings As Errors | Treats all warnings as errors. If there are any warning messages, an error message is emitted and compilation continues.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click General in the Category box.

You can also use #pragma warning() to control the level of warning reported at compile time.

On the command line, a space between /W and 0, 1, 2, 3, 4, or X is optional.

The Build Errors documentation describes the warnings, indicates each warning’s level, and indicates potential problems (rather than actual coding errors) with statements that may not compile as you intend.


/X (Ignore Standard Include Paths)

Home | Overview | How Do I | Compiler Options

This option prevents the compiler from searching for include files in directories specified in the PATH and INCLUDE environment variables. You can use this option with the Additional Include Directories (/Idirectory) option.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Preprocessor in the Category box.

Example

In the following command, /X tells the compiler to ignore locations specified by the PATH and INCLUDE environment variables, and /I specifies the directory in which to look for include files.

CL /X /I \ALT\INCLUDE MAIN.C


/Yc (Create Precompiled Header File)

Home | Overview | How Do I | Compiler Options

This option instructs the compiler to create a precompiled header (.PCH) file that represents the state of compilation at a certain point. (To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Precompiled Headers in the Category box.)

Command Line | Project Settings | Description
/Yc | Create Precompiled Header File | The compiler compiles all code up to the end of the base source file, or to the point in the base file where #pragma hdrstop occurs.
/Ycfilename | Through Header | The compiler compiles all code up to and including the .H file specified in the Through Header text box (filename).

The precompiled code is saved in a file with a name created from the base name of the file specified with the /Yc option and a .PCH extension. You can also use the /Fp option to specify a name for the precompiled header file.

If you use /Ycfilename (Through Header), the compiler compiles all code up to and including the specified file for subsequent use with the /Yu option.

Note If the options /Ycfilename and /Yu filename occur on the same command line and both reference, or imply, the same file name, /Ycfilename, takes precedence. This feature simplifies the writing of makefiles.

Example

Consider the following code:

#include <afxwin.h>   // Include header for class library
#include "resource.h" // Include resource definitions
#include "myapp.h"    // Include information specific to this app
...

When this code is compiled with the command

CL /YcMYAPP.H PROG.CPP

the compiler saves all the preprocessing for AFXWIN.H, RESOURCE.H, and MYAPP.H in a precompiled header file called MYAPP.PCH.

See Also Creating Precompiled Header Files


/Yd (Place Debug Info in Object File)

Home | Overview | How Do I | Compiler Options

This option, when used with the /Yc and /Z7 options, places complete debugging information in all object files created from a precompiled header (.PCH) file. Unless you need to distribute a library containing debugging information, use the /Zi option rather than /Z7 and /Yd. The /Yd option takes no argument.

Storing complete debugging information in every .OBJ file is necessary only to distribute libraries that contain debugging information. It slows compilation and requires considerable disk space. When /Yc and /Z7 are used without /Yd, the compiler stores common debugging information in the first .OBJ file created from the .PCH file. The compiler does not insert this information into .OBJ files subsequently created from the .PCH file; it inserts cross-references to the information. No matter how many .OBJ files use the .PCH file, only one .OBJ file contains the common debugging information.

Although this default behavior results in faster build times and reduces disk-space demands, it is undesirable if a small change requires rebuilding the .OBJ file containing the common debugging information. In this case, the compiler must rebuild all .OBJ files containing cross-references to the original .OBJ file. Also, if a common .PCH file is used by different projects, reliance on cross-references to a single .OBJ file is difficult.

Note The /Yd option is implied with use of the Automatic Use Of Precompiled Headers (/YX) option.


/Yu (Use Precompiled Header File)

Home | Overview | How Do I | Compiler Options

This option instructs the compiler to use an existing precompiled header in the current compilation.

Command Line | Project Settings | Description
/Yu | Use Precompiled Header File | This option specifies using a precompiled header (.PCH) file during builds. The PCH must have been created using Create Precompiled Header File (/Yc).
/Yufilename | Through Header | Type the name of a header (.H) file in the Through Header text box. The compiler treats all code occurring before the .H file as precompiled. It skips to just beyond the #include directive associated with the .H file, uses the code contained in the .PCH file, and then compiles all code after filename.

On the command line, no space is allowed between /Yu and filename.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Precompiled Headers in the Category box.

When you specify the /Yu option without a file name, your source program must contain #pragma hdrstop pragma that specifies the file name. The compiler skips to the location of that pragma, restores the compiled state from the precompiled header file specified by the pragma, and then compiles only code that follows the pragma. If #pragma hdrstop does not specify a file name, the compiler looks for a file with a name derived from the base name of the source file with a .PCH extension.

If you specify the /Yu option without a file name and fail to specify a hdrstop pragma, an error message is generated and the compilation is unsuccessful.

Note If the options /Ycfilename and /Yufilename occur on the same command line and both reference, or imply, the same file name, /Ycfilename, takes precedence. This feature simplifies the writing of makefiles.

Examples

If the following code:

#include <afxwin.h>   // Include header for class library
#include "resource.h" // Include resource definitions
#include "myapp.h"    // Include information specific to this app
...

is compiled with the command line:

CL /YuMYAPP.H PROG.CPP

the compiler does not process the three include statements but uses precompiled code from MYAPP.PCH, thereby saving the time involved in preprocessing all three of the files (and any files they might include).

You can use the /Fp option with the /Yu option to specify the name of the .PCH file if the name is different from either the file name argument to /Yc or the base name of the source file, as in the following:

CL /YuMYAPP.H /FpMYPCH.PCH PROG.CPP

This command specifies a precompiled header file named MYPCH.PCH. The compiler uses its contents to restore the precompiled state of all header files up to and including MYAPP.H. The compiler then compiles the code that occurs after the MYAPP.H include statement.


Consistency Rules for Per-File Use of Precompiled Headers

Home | Overview | How Do I | Compiler Options

When you use a PCH, the compiler assumes the same compilation environment—using consistent compiler options, pragmas, and so on—that was in effect when you created the PCH, unless you specify otherwise. If the compiler detects an inconsistency, it issues a warning and identifies the inconsistency where possible. Such warnings do not necessarily indicate a problem with the PCH; they simply warn you of possible conflicts. The consistency requirements for PCHs are explained in the following list:

Compiler Option Consistency

The following compiler options can trigger an inconsistency warning when using a PCH:

  • Macros created using the Preprocessor (/D) option must be the same between the compilation that created the PCH and the current compilation. The state of defined constants is not checked, but unpredictable results can occur if these change.

  • PCHs do not work with the /E and /EP options.

  • PCHs must be created using either the Generate Browse Info (/FR) option or the Exclude Local Variables (/Fr) option before subsequent compilations that use the PCH can use these options.

C 7.0-Compatible (/Z7)

If this option is in effect when the PCH is created, subsequent compilations that use the PCH can use the debugging information.

If the C 7.0-Compatible (/Z7) option is not in effect when the PCH is created, subsequent compilations that use the PCH and that option trigger a warning. The debugging information is placed in the current .OBJ file, and local symbols defined in the PCH are not available to the debugger.

Include Path Consistency

A PCH does not contain information about the include path that was in effect when it was created. When you use a .PCH file, the compiler always uses the include path specified in the current compilation.

Source File Consistency

When you specify the Use Precompiled Header File (/Yu) option, the compiler ignores all preprocessor directives (including pragmas) that appear in the source code that will be precompiled. The compilation specified by such preprocessor directives must be the same as the compilation used for the Create Precompiled Header File (/Yc) option.

Pragma Consistency

Pragmas processed during the creation of a PCH usually affect the file with which the PCH is subsequently used. The comment and message pragmas do not affect the remainder of the compilation.

The following pragmas are retained as part of a PCH. They do affect the remainder of a compilation that uses the PCH.

alloc_text | include_alias | pack
auto_inline | init_seg | pointers_to_members
check_stack | inline_depth | setlocale
code_seg | inline_recursion | vtordisp
data_seg | intrinsic | warning
function | optimize |


/YX (Automatic Use of Precompiled Headers)

Home | Overview | How Do I | Compiler Options

This option instructs the compiler to use a precompiled header file (PCH) if one exists or to create one if none exists. The file is created in the current directory. You can use the /Fp option to change the default name and location of the precompiled header. (To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Precompiled Headers in the Category box.)

Command Line Project Settings Description
/YX Automatic Use of Precompiled Headers
  • Creates a file named project.PCH if it doesn’t already exist, and compiles only header (.H) files into this .PCH file.

  • If you have no project open, it creates a file named VC50.PCH.

  • The inclusion of .H files stops when the compiler encounters the first declaration, definition, hdrstop pragma, or #line directive in the source file being compiled with the option, or after the .H file specified in the Through Header text box.

  • In subsequent compilations, the PCH is used after the compiler makes its final consistency check.

  • See Consistency Rules for /YX.
/YXfilename Through Header
  • When creating a PCH, the compiler compiles all code up to and including the .H file specified in the Through Header text box (filename).

  • When using a PCH, the compiler treats all code occurring before the specified .H file as precompiled. It skips to just beyond the #include directive associated with the .H file, uses the code contained in the .PCH file, and then compiles all code after filename.

The header files precompiled by /YX are determined by the compiler, which may elect to use a subset of header files available to improve the number of cases where the resulting precompiled header can be used.

Although it is usually best to let the compiler determine which header files to use, you can selectively precompile header files by placing a hdrstop pragma in the source file between two #include directives. All header files before the hdrstop pragma are precompiled; those after are not. When used with /YX, any filename specified with the hdrstop pragma is ignored. If any subsequent compilation using the precompiled header does not contain an identical hdrstop pragma at the same point in the source file, the compiler builds a new precompiled header.

Use of the /YX option implies use of the /Yd option (duplicate debugging information in all object files).

Example

The following command line uses /YX to create or use a precompiled header named VC50.PCH:

CL /YX MYPROG.CPP

The following command line creates a precompiled header named MYPROG.PCH and places it in the \PROJPCH directory:

CL /YX /Fp\PROJPCH\MYPROG.PCH MYPROG.CPP


Consistency Rules for /YX

Home | Overview | How Do I | Compiler Options

If a precompiled header file exists (either MSVC.PCH or one specified by /Fp), it is compared with the current compilation for consistency. The following requirements must be met; otherwise, a new precompiled header file is created, and the new file replaces the old.

  • The current compiler options must match those specified when the precompiled header was created. However, if a significant portion of the source code of the currently compiled module matches the module for which the PCH was created, the compiler can create a new PCH for the matching part. This subsetting action increases the number of modules for which a PCH can be used.

  • The current working directory must match that specified when the PCH was created.

  • The order and values of all #include and #pragma preprocessor directives must match those specified when the PCH was created. These, along with #define directives, are checked as they appear during subsequent compilations that use the PCH. The #pragma directives must be nearly identical—multiple spaces outside of strings are treated as a single space to allow for different programming styles.

  • The values of #define directives must match. However, a group of #define directives in sequence need not occur in exactly the same order since there are no semantic order dependencies for #define directives.

  • The value and order of include paths specified on the command line with /I (Additional Include Directories) options must match those specified when the precompiled header was created.

  • The timestamps of all the header files (all files specified with #include directives) used to build the precompiled header must match those that existed when the precompiled header was created.


/Z7, /Zd, /Zi, /ZI (Debug Info)

Home | Overview | How Do I | Compiler Options

The Debug Info options select the type of debugging information created for your program and whether this information is kept in object (.OBJ) files or in a program database (PDB).

Command Line | Project Settings | Description
None of these options | None | Produces no debugging information, so compilation is faster.
/Zd | Line Numbers Only | Produces an .OBJ file or executable (.EXE) file containing only global and external symbol and line-number information (no symbolic debugging information). Use this option if you want to reduce the size of the .EXE file, or if you don’t want to use the debugger’s expression evaluator (requires symbolic information).
/Z7 | C 7.0- Compatible | Produces an .OBJ file and an .EXE file containing line numbers and full symbolic debugging information for use with the debugger. The symbolic debugging information includes the names and types of variables, as well as functions and line numbers.
/Zi | Program Database | Produces a program database (PDB) that contains type information and symbolic debugging information for use with the debugger. The symbolic debugging information includes the names and types of variables, as well as functions and line numbers.
/ZI | Program Database for "Edit & Continue" | Produces a program database, as described above, in a format that supports the Edit and Continue feature. If you want to use Edit and Continue debugging, you must use this option. Use of the /ZI switch will disable any #pragma optimize statements in your code.

To find these options in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click General in the Category box.

The compiler names the program database project.PDB. If you compile a file without a project, the compiler creates a database named VC50.PDB. The compiler embeds the name of the PDB in each .OBJ file created using this option, pointing the debugger to the location of symbolic and line-number information. When you use this option, your .OBJ files will be smaller, because debugging information is stored in the .PDB file rather than in .OBJ files.

If you create a library from objects that were compiled using this option, the associated .PDB file must be available when the library is linked to a program. Thus, if you distribute the library, you must distribute the PDB.

Note To create a library that contains debugging information without using .PDB files, you must select the compiler’s C 7.0-Compatible (/Z7) option and clear the linker’s Use Program Database (/PDB:NONE) option. If you use the precompiled headers options, debugging information for both the precompiled header and the rest of the source code is placed in the PDB. The /Yd option is ignored when the Program Database option is specified.


/Za, /Ze (Disable Language Extensions)

Home | Overview | How Do I | Compiler Options

The Microsoft C compiler supports the ANSI C standard. In addition, it offers a number of features beyond those specified in the ANSI C standard. These features are available when the /Ze option, the default, is specified and are not available when the /Za option is specified. See Microsoft Extensions to C for more information.

Command Line | Project Settings | Description
/Za | Disable Language Extensions (check box selected) | ANSI C compatibility. Language constructs not compatible with ANSI C are flagged as errors.
/Ze | (Check box cleared) | Enables Microsoft extensions.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Customize in the Category box.

Note If you use the Disable Language Extensions (/Za) option, the Improve Float Consistency (/Op) option is used to improve the consistency of floating-point tests for equality and inequality. This use of /Op with /Za is for strict ANSI conformance and is the only situation under which /Op is selected by default. The /Op– option is provided to override the default selection of /Op with /Za. Specify /Op– in the Common/Project/Source File Options text box (or on the command line), after /Za, to disable /Op. For more information, also see Generate Intrinsic Functions (/Oi).

Disable language extensions if you plan to port your program to other environments. The compiler treats extended keywords as simple identifiers, disables the other Microsoft extensions, and automatically defines the __STDC__ predefined macro for C programs.


Microsoft Extensions to C

Home | Overview | How Do I | Compiler Options

The following are Microsoft extensions to the ANSI C standard:

Keywords

The keywords __based, __cdecl, __declspec, __except, __fastcall, __finally, __leave, __stdcall, and __try are Microsoft-specific.

Casts

The Microsoft compiler supports the following two non-ANSI casts:

  • Use of non-ANSI casts to produce l-values:
    char *p;
(( int * ) p )++;

    The preceding example could be rewritten to conform with the ANSI C standard as follows:

    p = ( char * )(( int * )p + 1 );
  • Non-ANSI casting of a function pointer to a data pointer:
    int ( * pfunc ) ();
int *pdata;
pdata = ( int * ) pfunc;

    To perform the same cast while maintaining ANSI compatibility, you must cast the function pointer to an int before casting it to a data pointer:

    pdata = ( int * ) (int) pfunc;

Variable-Length Argument Lists

The Microsoft compiler supports use of a function declarator that specifies a variable number of arguments, followed by a function definition that provides a type instead:

void myfunc( int x, ... );
void myfunc( int x, char * c )
{ }

Single-Line Comments

The Microsoft C compiler supports single-line comments, which are introduced with two forward slash (//) characters:

// This is a single-line comment.

Scope

The Microsoft C compiler supports the following scope-related features:

  • Redefinitions of extern items as static:
    extern int clip();
static int clip()
{}
  • Use of benign typedef redefinitions within the same scope:
    typedef int INT;
typedef int INT;
  • Function declarators have file scope:
    void func1()
{
    extern int func2( double );
}
void main( void )
{
    func2( 4 );    //  /Ze passes 4 as type double
}                  //  /Za passes 4 as type int
  • Use of block-scope variables initialized with nonconstant expressions:
    int clip( int );
int bar( int );
void main( void )
{
    int array[2] = { clip( 2 ), bar( 4 ) };
}
int clip( int x )
{
    return x;
}
int bar( int x )
{
    return x;
}

Data Declarations and Definitions

The Microsoft C compiler supports the following data declaration and definition features:

  • Mixed character and string constants in an initializer:
    char arr[5] = {'a', 'b', "cde"};
  • Bit fields with base types other than unsigned int or signed int.

  • Declarators without either a storage class or a type:
    x;
void main( void )
{
    x = 1;
}
  • Unsized arrays as the last field in structures and unions:
    struct zero
{
    char *c;
    int zarray[];
};
  • Unnamed (anonymous) structures:
    struct
{
    int i;
    char *s;
};
  • Unnamed (anonymous) unions:
    union
{
    int i;
    float fl;
};
    • Unnamed members:
    struct s
{
unsigned int flag : 1;
unsigned int : 31;
}

Intrinsic Floating-Point Functions

The Microsoft compiler supports inline generation of the x86 Specific —> atan, atan2, cos, exp, log, log10, sin, sqrt, and tan functions END x86 Specific when the Generate Intrinsic Functions (/Oi) option is specified. For C, ANSI conformance is lost when these intrinsics are used, because they do not set the errno variable.


/Zg (Generate Function Prototypes)

Home | Overview | How Do I | Compiler Options

This option creates a function prototype for each function defined in the source file, but does not compile the source file.

The function prototype includes the function return type and an argument type list. The argument type list is created from the types of the formal parameters of the function. Any function prototypes already present in the source file are ignored.

The list of prototypes is written to standard output. You may find this list helpful to verify that actual arguments and formal parameters of a function are compatible. You can save the list by redirecting standard output to a file. Then you can use #include to make the list of function prototypes a part of your source file. Doing so causes the compiler to perform argument type checking.

If you use the /Zg option and your program contains formal parameters that have struct, enum, or union type (or pointers to such types), the prototype for each struct, enum, or union type must have a tag.


/Zl (Omit Default Library Name)

Home | Overview | How Do I | Compiler Options

This option omits the default library name from the .OBJ file. By default, CL puts the name of the library into the .OBJ file to direct the linker to the correct library. For more information on the default library, see Use Run-Time Library.

You can use /Zl to compile .OBJ files you plan to put into a library. Although omitting the library name saves only a small amount of space for a single .OBJ file, the total space saved is significant in a library that contains many object modules.


/Zm (Specify Memory Allocation Limit)

Home | Overview | How Do I | Compiler Options

The /Zmnumber option determines the compiler's memory allocation limit. The number argument is a scaling factor, with a default value of 100 (that is, 100%). The maximum value is 2000.

The compiler uses a number of discrete heaps, each of which has a finite limit. The total of the size limits for all heaps is about 105 MB, but when any one heap is exhausted, the compiler cannot continue. Memory is allocated only as needed; the 105 MB limit is just to keep from using too much memory. Exceeding any one of the discrete-heap size limits occurs only in rare circumstances involving very large or very complex programs. Should your program exceed one of these limits, use /Zm to scale the total size of all the limits. For example, when /Zm200 is specified, the total of all heap size limit is 210MB.

Note In most cases, use of this compiler option is not necessary. Use it if compiling your program causes error message C1076: "compiler limit : internal heap limit reached."


/Zn (Turn Off SBRPACK)

Home | Overview | How Do I | Compiler Options

Use the /Zn option with either the /FR or /Fr option to turn off packing of browser files. The /FR or /Fr option creates an .SBR file, which CL packs by default.

The Microsoft Browser Database Maintenance Utility (BSCMAKE) uses the .SBR file to generate a .BSC file that you can examine in Browse windows. Packing allows BSCMAKE to run faster and also saves disk space. However, BSCMAKE's /Iu option requires an unpacked .SBR file in order to include unreferenced symbols. Use /Zn only if you need to include unreferenced symbols or if compilation time is critical. You can pack the .SBR file later by using the Microsoft Browse Information Compactor (SBRPACK).


/Zp (Struct Member Alignment)

Home | Overview | How Do I | Compiler Options

The Struct Member Alignment (/Zpn) option controls how the members of a structure are packed into memory and specifies the same packing for all structures in a module. When you specify this option, each structure member after the first is stored on either the size of the member type or n-byte boundaries (where n is 1, 2, 4, 8, or 16), whichever is smaller.

You should not use this option unless you have specific alignment requirements.

Command Line | Project Settings | Result
/Zp1 | 1 Byte | Packs structures on 1-byte boundaries
/Zp2 | 2 Bytes | Packs structures on 2-byte boundaries
/Zp4 | 4 Bytes | Packs structures on 4-byte boundaries
/Zp8 | 8 Bytes | Packs structures on 8-byte boundaries (default)
/Zp16 | 16 Bytes | Packs structures on 16-byte boundaries
/Zp | Not applicable | Specifies the same packing for all structures in a module.

To find this option in the development environment, click Settings on the Project menu. Then click the C/C++ tab, and click Code Generation in the Category box.

You can also use #pragma pack to control structure packing.


/Zs (Syntax Check Only)

Home | Overview | How Do I | Compiler Options

This option tells the compiler to check only the syntax of the source files on the command line. No output files are created. Error messages are written to standard output. The /Zs option provides a quick way to find and correct syntax errors before you compile and link a source file.


Linker Reference

Home | Overview | How Do I | FAQ | Details

LINK is a 32-bit tool that links Common Object File Format (COFF) object files and libraries to create a 32-bit executable (.EXE) file or dynamic-link library (DLL).

Following is a comprehensive list of options for LINK.EXE. For information on how to specify an option, see Set Linker Options.

This section also includes information on Compiler-Controlled LINK Options, LINK Input Files, and LINK Output.

Option | Action
/ALIGN :number | Specifies the alignment of each section
/BASE :{address | @filename,key} | Sets a base address for the program
/COMMENT :["]comment["] | Inserts a comment string into header
/DEBUG | Creates debugging information
/DEBUGTYPE :CV /DEBUGTYPE :COFF /DEBUGTYPE :BOTH | Creates particular formats of debugging information
/DEF :filename | Passes a module-definition (.DEF) file to the linker
/DEFAULTLIB:library | Searches specified library when resolving external references
/DELAY | Controls the delayed loading of DLLs
/DELAYLOAD | Causes the delayed loading of the specified DLL
/DLL | Builds a DLL
/DRIVER[:UPONLY] | Creates a Windows NT kernel mode driver
/ENTRY :function | Sets the starting address
/EXETYPE :DYNAMIC | Builds a virtual device driver
/EXPORT | Exports a function
/FIXED[:NO] | Creates a program that can be loaded only at its preferred base address
/FORCE[:{MULTIPLE|UNRESOLVED}] | Forces link to complete in spite of unresolved or multiply defined symbols
/GPSIZE :# | Specifies the size of communal variables for MIPS and Alpha platforms
/HEAP :reserve[,commit] | Sets the size of the heap in bytes
/IMPLIB :filename | Overrides the default import library name
/INCLUDE :symbol | Forces symbol references
/INCREMENTAL :{YES|NO} | Controls incremental linking
/LARGEADDRESSAWARE | Tells the compiler that the application supports addresses larger than two gigabytes.
/LIBPATH :path | Allows the user to override the environmental library path
/LINK50COMPAT | Generates import libraries in Visual C++ Version 5.0 format
/MACHINE :{IX86|ALPHA|ARM|MIPS|MIPSR41XX|PPC|SH3|SH4} | Specifies the target platform
/MAP | Creates a map file
/MAPINFO:{EXPORTS|FIXUPS|LINES} | Includes the specified information in the map file
/MERGE :from=to | Combines sections
/NODEFAULTLIB[:library] | Ignores all (or specified) default libraries when resolving external references
/NOENTRY | Creates a resource-only DLL
/NOLOGO | Suppresses startup banner
/OPT :{REF|NOREF|ICF[,iterations]|NOICF} | Controls LINK optimizations
/ORDER :@filename | Places COMDATs into the image in a predetermined order
/OUT :filename | Specifies the output file name
/PDB :filename | Creates a program database (.PDB) file
/PDBTYPE :{con[solidate]|sept[ypes]} | Specifies where to store the Program Database (PDB) debug type information.
/PROFILE | Enables profiling (creates a mapfile)
/RELEASE | Sets the checksum in the .EXE header
/SECTION :name,attributes | Overrides the attributes of a section
/STACK :reserve[,commit] | Sets the size of the stack in bytes
/STUB :filename | Attaches an MS-DOS stub program to a Win32 program
/SUBSYSTEM :{CONSOLE|WINDOWS|NATIVE|POSIX|WINDOWSCE} [,major[.minor] ] | Tells the operating system how to run the .EXE file
/SWAPRUN :{NET|CD} | Tells the operating system to copy the linker output to a swap file before running it
/VERBOSE[:LIB] | Prints linker progress messages
/VERSION :major[.minor] | Assigns a version number
/VXD | Creates a virtual device driver (VxD)
/WARN[:level] | Specifies warning level
/WS:AGGRESSIVE | Aggressively trim process memory

For related information, see Compiler-Controlled LINK Options.


Compiler-Controlled LINK Options

Home | Overview | How Do I | FAQ | Details | Linker Options

The CL compiler automatically calls LINK unless you specify the /c option. CL provides some control over the linker through command-line options and arguments. The following table summarizes the features in CL that affect linking.

Compiler-Controlled LINK Options

CL command-line specification | CL action that affects LINK
Any file name extension other than .C, .CXX, .CPP, or .DEF | Passes a file name as input to LINK
filename.DEF | Passes /DEF:filename.DEF
/Fnumber | Passes /STACK:number
/Fdfilename | Passes /PDB:filename
/Fefilename | Passes /OUT:filename
/Fmfilename | Passes /MAP:filename
/Gy | Creates packaged functions (COMDATs); enables function-level linking
/LD | Passes /DLL
/LDd | Passes /DLL
/link | Passes remainder of command line to LINK
/MD, /ML, or /MT | Places a default library name in the .OBJ file
/MDd, /MLd, or /MTd | Places a default library name in the .OBJ file. Defines the symbol _DEBUG.
/nologo | Passes /NOLOGO
/Zd | Passes /DEBUG /DEBUGTYPE:COFF
/Zi or /Z7 | Passes /DEBUG /DEBUGTYPE:CV
/Zl | Omits default library name from .OBJ file

For more information on compiler options, see Compiler Option Reference.


LINK Input Files

Home | Overview | FAQ | Details | Linker Options

You provide the linker with files that contain objects, import and standard libraries, resources, module definitions, and command input. LINK does not use file extensions to make assumptions about the contents of a file. Instead, LINK examines each input file to determine what kind of file it is.

Note LINK no longer takes a semicolon (or any other character) as the start of a comment in response files and order files. Semicolons are recognized only as start of comments in module-definition files (.DEF).

LINK uses the following types of input files:

  • .OBJ files

  • .LIB files

  • .EXP files

  • .DEF files

  • .PDB files

  • .RES files

  • .EXE files

  • .TXT files

  • .ILK files


.OBJ Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

LINK accepts .OBJ files that are either Common Object File Format (COFF) or 32-bit Object Module Format (OMF). Microsoft’s compiler creates COFF .OBJ files. LINK automatically converts 32-bit OMF objects to COFF. See Set Linker Options for related information.


.LIB Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

LINK accepts COFF standard libraries and COFF import libraries, both of which usually have the extension .LIB. Standard libraries contain objects and are created by the LIB tool. Import libraries contain information about exports in other programs and are created either by LINK when it builds a program that contains exports or by the LIB tool. For information on using LIB to create standard or import libraries, see LIB Reference. For details on using LINK to create an import library, see the /DLL option.

A library is specified to LINK as either a file name argument or a default library. LINK resolves external references by searching first in libraries specified on the command line, then in default libraries specified with the /DEFAULTLIB option, and then in default libraries named in .OBJ files. If a path is specified with the library name, LINK looks for the library in that directory. If no path is specified, LINK looks first in the directory that LINK is running from, and then in any directories specified in the LIB environment variable.

LINK cannot link a library of 32-bit OMF objects created by the 16-bit version of LIB. To use an OMF library, you must first use the 16-bit LIB (not provided in Visual C++ for Windows NT) to extract the objects. You can then either link the OMF objects or use the 32-bit LIB to convert them to COFF and put them into a library. You can also use the EDITBIN.EXE tool to convert an OMF object to COFF.


.EXP Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

Export (.EXP) files contain information about exported functions and data items. When LIB creates an import library, it also creates an .EXP file. You use the .EXP file when you link a program that both exports to and imports from another program, either directly or indirectly. If you link with an .EXP file, LINK does not produce an import library, because it assumes that LIB already created one. For details about .EXP files and import libraries, see Working with Import Libraries and Export Files.


.DEF Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

Module-definition (.DEF) files provide the linker with information about exports, attributes, and other information about the program to be linked. Use the /DEF option to specify the .DEF file name. Because LINK provides options and other features that can be used instead of module-definition statements, .DEF files are generally not necessary.


.PDB Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

Object (.OBJ) files compiled using the /Zi option contain the name of a program database (PDB). You do not specify the object’s PDB file name to the linker; LINK uses the embedded name to find the PDB if it is needed. This also applies to debuggable objects contained in a library; the PDB for a debuggable library must be available to the linker along with the library.

LINK also uses a PDB to hold debugging information for the .EXE file or .DLL file. The program’s PDB is both an output file and an input file, because LINK updates the PDB when it rebuilds the program.


.RES Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

You can specify a .RES file when linking a program. The .RES file is created by the resource compiler (RC). LINK automatically converts .RES files to COFF. The CVTRES.EXE tool must be in the same directory as LINK.EXE or in a directory specified in the PATH environment variable.


.EXE Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

The MS-DOS Stub File Name (/STUB) option specifies the name of an .EXE file that runs with MS-DOS. LINK examines the specified file to be sure that it is a valid MS-DOS program.


.TXT Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

LINK expects various text files as additional input. The command-file specifier (@) and the Base Address (/BASE), /DEF, and /ORDER options all specify text files. These files can have any extension, not just .TXT.


.ILK Files as Linker Input

Home | Overview | FAQ | Details | Linker Options

When linking incrementally, LINK updates the .ILK status file that it created during the first incremental link. This file has the same base name as the .EXE file or .DLL file, and it has the extension .ILK. During subsequent incremental links, LINK updates the .ILK file. If the .ILK file is missing, LINK performs a full link and creates a new .ILK file. If the .ILK file is unusable, LINK performs a nonincremental link. For details about incremental linking, see the Link Incrementally (/INCREMENTAL) option.


LINK Output

Home | Overview | FAQ | Details | Linker Options

Link output includes .EXE files, DLLs, map files, and messages.

Output Files

The default output file from LINK is an .EXE file. If the /DLL option is specified, LINK builds a .DLL file. You can control the output file name with the Output File Name (/OUT) option.

In incremental mode, LINK creates an .ILK file to hold status information for later incremental builds of the program. For details about .ILK files, see .ILK Files. For more information about incremental linking, see the Link Incrementally (/INCREMENTAL) option.

When LINK creates a program that contains exports (usually a DLL), it also builds a .LIB file, unless an .EXP file was used in the build. You can control the import library file name with the /IMPLIB option.

If the Generate Mapfile (/MAP) option is specified, LINK creates a map file.

If the Generate Debug Info (/DEBUG) and Microsoft Format (/DEBUGTYPE:CV) options are specified, LINK creates a PDB to contain debugging information for the program.

Other Output

When you type link without any other command-line input, LINK displays a usage statement that summarizes its options.

LINK displays a copyright and version message and echoes command-file input, unless the Suppress Startup Banner (/NOLOGO) option is used.

You can use the Print Progress Messages (/VERBOSE) option to display additional details about the build.

LINK issues error and warning messages in the form LNKnnnn. This error prefix and range of numbers is also used by LIB, DUMPBIN, and EDITBIN. You can control the display of warnings with the /WARN option. See Fix Build Errors for information on getting help on error and warning messages.


Reserved Words

Home | Overview | FAQ | Details | Linker Options

The following words are reserved by the linker. These names can be used as arguments in module-definition statements only if the name is enclosed in double quotation marks (").

APPLOADER1 | INITINSTANCE2 | PRELOAD
BASE | IOPL | PRIVATE
CODE | LIBRARY1 | PROTMODE2
CONFORMING | LOADONCALL1 | PURE1
DATA | LONGNAMES2 | READONLY
DESCRIPTION | MOVABLE1 | READWRITE
DEV386 | MOVEABLE1 | REALMODE1
DISCARDABLE | MULTIPLE | RESIDENT
DYNAMIC | NAME | RESIDENTNAME1
EXECUTE-ONLY | NEWFILES2 | SECTIONS
EXECUTEONLY | NODATA1 | SEGMENTS
EXECUTEREAD | NOIOPL1 | SHARED
EXETYPE | NONAME | SINGLE
EXPORTS | NONCONFORMING1 | STACKSIZE
FIXED1 | NONDISCARDABLE | STUB
FUNCTIONS2 | NONE | VERSION
HEAPSIZE | NONSHARED | WINDOWAPI
IMPORTS | NOTWINDOWCOMPAT1 | WINDOWCOMPAT
IMPURE1 | OBJECTS | WINDOWS
INCLUDE2 | OLD1 |

1 The linker emits a warning (“ignored”) when it encounters this term. However, the word is still reserved.

2 The linker ignores this word, but emits no warning.


/ALIGN (Section Alignment)

Home | Overview | How Do I | Linker Options

Syntax

/ALIGN:number

This option specifies the alignment of each section within the linear address space of the program. The number argument is in bytes and must be a power of two. The default is 4K. The linker issues a warning if the alignment produces an invalid image.


/BASE (Base Address)

Home | Overview | How Do I | Linker Options

The Base Address (/BASE:{address | @filename,key}) option sets a base address for the program, overriding the default location for an .EXE file (at 0x400000) or a DLL (at 0x10000000). The operating system first attempts to load a program at its specified or default base address. If sufficient space is not available there, the system relocates the program. To prevent relocation, use the /FIXED option.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click General in the Output box.

Type the preferred base address in the Base Address text box (or in the address argument on the command line). The linker rounds the specified number up to the nearest multiple of 64K.

On the command line, another way to specify the base address is by using the filename preceded by an at sign (@), and a key into the file. The filename is a text file that contains the locations and sizes of all the DLLs your program will use. The linker looks for filename in either the specified path or, if no path is specified, in directories specified in the LIB environment variable. Each line in filename represents one DLL and has the following syntax:

key address size ;comment

The key is a string of alphanumeric characters and is not case sensitive. It is usually the name of a DLL, but it need not be. The key is followed by a base address in C-language, hexadecimal, or decimal notation and a maximum size. All three arguments are separated by spaces or tabs. The linker issues a warning if the specified size is less than the virtual address space required by the program. A comment is specified by a semicolon (;) and can be on the same or a separate line. The linker ignores all text from the semicolon to the end of the line. This example shows part of such a file:

main   0x00010000    0x08000000    ; for PROJECT.EXE
one    0x28000000    0x00100000    ; for DLLONE.DLL
two    0x28100000    0x00300000    ; for DLLTWO.DLL

If the file that contains these lines is called DLLS.TXT, the following example command applies this information:

link dlltwo.obj /dll /base:dlls.txt,two

You can reduce paging and improve performance of your program by assigning base addresses so that DLLs do not overlap in the address space.

Another way to set the base address is with the BASE argument in a NAME or LIBRARY statement. The /BASE and /DLL options together are equivalent to the LIBRARY statement.


/COMMENT (Insert Comment into Header)

Home | Overview | How Do I | Linker Options

Syntax

/COMMENT:["]comment["]

This option inserts a comment string into the header of an .EXE file or DLL, after the array of section headers. The type of operating system determines whether the string is loaded into memory. This comment string, unlike the comment specified with the DESCRIPTION statement in a .DEF file, is not inserted into the data section. Comments are useful for embedding copyright and version information.

To specify a comment that contains spaces or tabs, enclose it in double quotation marks ("). LINK removes the quotation marks before inserting the string. If more than one /COMMENT option is specified, LINK concatenates the strings and places a null byte at the end of each string.


/DEBUG (Generate Debug Info)

Home | Overview | How Do I | Linker Options

This option creates debugging information for the .EXE file or DLL. When specifying this option, you will also specify a DEBUGTYPE option. (To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Debug in the Category box.)

The linker puts the debugging information into a program database (PDB). It updates the PDB during subsequent builds of the program.

An .EXE file or DLL created for debugging contains the name and path of the corresponding PDB. The debugger reads the embedded name and uses the PDB when you debug the program. The linker uses the base name of the program and the extension .PDB to name the program database, and embeds the path where it was created. To override this default, set the Use Program Database linker option (/PDB:filename on the command line) and specify a different file name in the Program Database Name text box.

The compiler’s Line Numbers Only (/Zd) or C7 Compatible (/Z7) option causes the compiler to leave the debugging information in the .OBJ files. You can also use the Program Database (/Zi) compiler option to store the debugging information in a PDB for the .OBJ file. The linker looks for the object’s PDB first in the absolute path written in the .OBJ file, and then in the directory that contains the .OBJ file. You cannot specify an object's PDB file name or location to the linker.

If the Use Program Database option is not selected (or if /PDB:NONE is specified on the command line), the linker does not create a PDB, but instead puts the debugging information into the .EXE file or DLL.

The Generate Debug Info (/DEBUG) option changes the defaults for the /OPT option from REF to NOREF and from ICF to NOICF.


/DEBUGTYPE (Debugging Format)

Home | Overview | How Do I | Linker Options

These options are available when the /DEBUG (Generate Debug Info) option is used.

Command Line | Project Settings | Description
/DEBUGTYPE:CV | Microsoft Format | This option creates Microsoft Format debugging information.
/DEBUGTYPE:COFF | COFF Format | This option creates Common Object File Format (COFF) debugging information.
/DEBUGTYPE:BOTH | Both Formats | This option creates both COFF debugging information and Microsoft Format debugging information.

(To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Debug in the Category box.) To use Microsoft Format debugging information, select the Microsoft Format option button under Debug Info. If the Generate Debug Info check box is not selected, this choice is unavailable. On the command line, if /DEBUG is specified, the default type is /DEBUGTYPE:CV; if /DEBUG is not specified, /DEBUGTYPE is ignored.

Some debuggers require COFF debugging information. To use COFF-format debugging information, select the COFF Format option button under Debug Info. If the Generate Debug Info check box is not selected, this choice is unavailable. On the command line, specify /DEBUGTYPE:COFF; if /DEBUG is not specified, /DEBUGTYPE is ignored.

When /DEBUGTYPE:COFF or /DEBUGTYPE:BOTH is set, incremental linking is disabled. The linker must call the CVPACK.EXE tool to process the Microsoft Format debugging information. CVPACK must be in the same directory as LINK or in a directory in the PATH environment variable.


/DEF (Specify Module-Definition File)

Home | Overview | How Do I | Linker Options

Syntax

/DEF:filename

This option passes a module-definition (.DEF) file to the linker. Only one .DEF file can be specified to LINK. For details about .DEF files, see Module-Definition Files.

When a .DEF file is used in a build, no matter whether the main output file is an .EXE file or a DLL, LINK creates an import library (.LIB) and an export file (.EXP). These files are created regardless of whether the main output file contains exports.

Do not specify this option within the development environment; this option is for use only on the command line. To specify a .DEF file, add it to the project along with other files.


/DEFAULTLIB (Specify Default Library)

Home | Overview | How Do I | Linker Options

Syntax

/DEFAULTLIB:library

This option adds one library to the list of libraries that LINK searches when resolving references. A library specified with /DEFAULTLIB is searched after libraries specified on the command line and before default libraries named in .OBJ files.

The Ignore All Default Libraries (/NODEFAULTLIB) option overrides /DEFAULTLIB:library. The Ignore Libraries (/NODEFAULTLIB:library) option overrides /DEFAULTLIB:library when the same library name is specified in both.


/DELAY (Delay Load Import Settings)

Home | Overview | How Do I | Linker Options

Syntax

/DELAY:{unload|nobind}

This option controls delayed loading of DDLs:

  • The unload qualifier tells the delay-load helper function to support explicit unloading of the DLL by resetting the IAT to its original form, invalidating IAT pointers and causing them to be overwritten.

  • The nobind qualifier tells the linker not to include a bindable IAT in the final image. The resulting image cannot be statically bound. (Images with bindable IATs may be statically bound prior to execution.)

To specify DLLs to delay load, use the /DELAYLOAD option.


/DELAYLOAD (Delay Load Import)

Home | Overview | How Do I | Linker Options

Syntax

/DELAYLOAD:dllname

This option causes delayed loading of DLLs. The dllname specifies a DLL to delay load. You can use this option as many times as necessary to specify as many DLLs as you choose. You must link your program with Delayimp.lib or implement your own delay-load helper function.

The /DELAY option specifies.


/DLL (Build a DLL)

Home | Overview | How Do I | Linker Options

This option builds a DLL as the main output file. A DLL usually contains exports that can be used by another program. There are three methods for specifying exports, listed in recommended order of use:

  1. The __declspec(dllexport) keyword in the source code

  2. An EXPORTS statement in a .DEF file

  3. An /EXPORT specification in a LINK command

A program can use more than one method.

Another way to build a DLL is with the LIBRARY module-definition statement. The /BASE and /DLL options together are equivalent to the LIBRARY statement.

Do not specify this option within the development environment; this option is for use only on the command line. This option is set when you select either MFC AppWizard (DLL) or Dynamic-Link Library on the Projects tab of the New dialog box.


/DRIVER (Windows NT Kernel Mode Driver)

Home | Overview | How Do I | Linker Options

Syntax

/DRIVER[:UPONLY]

Use this linker option to build a Windows NT kernel mode driver. The linker will perform some special optimizations if this option is selected. The UPONLY keyword causes the linker to add the IMAGE_FILE_UP_SYSTEM_ONLY bit to the characteristics in the output header to specify that it is a uniprocessor (UP) driver. The operating system will refuse to load a UP driver on a multiprocessor (MP) system.


/ENTRY (Entry-Point Symbol)

Home | Overview | How Do I | Linker Options

The Entry-Point Symbol (/ENTRY:function) option sets the starting address for an .EXE file or DLL. (To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Output in the Category box.)

Type a function name in the Entry-Point Symbol text box (or in the function argument on the command line). The function must be defined with the __stdcall calling convention. The parameters and return value must be defined as documented in the Win32 API for WinMain (for an .EXE file) or DllEntryPoint (for a DLL). It is recommended that you let the linker set the entry point so that the C run-time library is initialized correctly, and C++ constructors for static objects are executed.

By default, the starting address is a function name from the C run-time library. The linker selects it according to the attributes of the program, as shown in the following table.

Function name | Default for
mainCRTStartup (or wmainCRTStartup) | An application using /SUBSYSTEM:CONSOLE; calls main (or wmain)
WinMainCRTStartup (or wWinMainCRTStartup) | An application using /SUBSYSTEM:WINDOWS; calls WinMain (or wWinMain), which must be defined with __stdcall
_DllMainCRTStartup | A DLL; calls DllMain, which must be defined with __stdcall, if it exists

If the /DLL or /SUBSYSTEM option is not specified, the linker selects a subsystem and entry point depending on whether main or WinMain is defined.

The functions main, WinMain, and DllMain are the three forms of the user-defined entry point.


/EXETYPE (Executable File Type)

Home | Overview | How Do I | Linker Options

Syntax

/EXETYPE:DYNAMIC

The Executable File Type (/EXETYPE:DYNAMIC) option is used when building a virtual device driver (VxD). A VxD is linked using the /VXD option.

Specify DYNAMIC to create a dynamically-loaded VxD.


/EXPORT (Exports A Function)

Home | Overview | How Do I | Linker Options

Syntax

/EXPORT:entryname[=internalname][,@ordinal[,NONAME]][,DATA]

Note You can only use this linker option for a small number of exports. It is recommended that you use the EXPORTS statement in a .DEF file instead.

With this option, you can export a function from your program so that other programs can call the function. You can also export data. Exports are usually defined in a DLL.

The entryname is the name of the function or data item as it is to be used by the calling program. You can optionally specify the internalname as the function known in the defining program; by default, internalname is the same as entryname. The ordinal specifies an index into the exports table in the range 1 through 65,535; if you do not specify ordinal, LINK assigns one. The NONAME keyword exports the function only as an ordinal, without an entryname.

The DATA keyword specifies that the exported item is a data item. The data item in the client program must be declared using extern __declspec(dllimport).

There are three methods for exporting a definition, listed in recommended order of use:

  1. The __declspec(dllexport) keyword in the source code

  2. An EXPORTS statement in a .DEF file

  3. An /EXPORT specification in a LINK command

All three methods can be used in the same program. When LINK builds a program that contains exports, it also creates an import library, unless an .EXP file is used in the build.

LINK uses decorated forms of identifiers. The compiler decorates an identifier when it creates the .OBJ file. If entryname or internalname is specified to the linker in its undecorated form (as it appears in the source code), LINK attempts to match the name. If it cannot find a unique match, LINK issues an error message. Use the DUMPBIN tool to get the decorated form of an identifier when you need to specify it to the linker. For more information on decorated names, see Decorated Names.

Note Do not specify the decorated form of C identifiers that are declared __cdecl or __stdcall.


/FIXED (Fixed Base Address)

Home | Overview | How Do I | Linker Options

Syntax

/FIXED[:NO]

This option tells the operating system to load the program only at its preferred base address. If the preferred base address is unavailable, the operating system will not load the file. For more information, see /BASE (Base Address).

When /FIXED is specified, now the default setting, LINK does not generate a relocation section in the program. At run time, if the operating system is unable to load the program at that address, it issues an error message and does not load the program.

Specify /FIXED:NO to generate a relocation section in the program.

Some Win32 operating systems, especially those that coexist with MS-DOS®, must frequently relocate a program. A program created with the /FIXED option will not run on Win32s operating systems.

Do not use /FIXED when building device drivers for Windows NT.


/FORCE (Force File Output)

Home | Overview | How Do I | Linker Options

Syntax

/FORCE:{MULTIPLE|UNRESOLVED}

This option tells the linker to create a valid .EXE file or DLL even if a symbol is referenced but not defined or is multiply defined.

On the command line, the /FORCE option can take an optional argument:

  • Use /FORCE:MULTIPLE to create an output file whether or not LINK finds more than one definition for a symbol.

  • Use /FORCE:UNRESOLVED to create an output file whether or not LINK finds an undefined symbol.

A file created with this option may not run as expected. The linker will not link incrementally when the /FORCE option is specified.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Customize in the Category box.


/GPSIZE

Home | Overview | How Do I | Linker Options

Syntax

/GPSIZE:#

This option is for DEC™ Alpha and MIPS® platforms. Use it to control whether communal variables (uninitialized global data items) are allocated in .sdata or .bss. Communal variables smaller than or equal to the /GPSIZE value are allocated in .sdata. Communal variables larger than this value are allocated in .bss.


/HEAP (Set Heap Size)

Home | Overview | How Do I | Linker Options

Syntax

/HEAP:reserve[,commit]

This option sets the size of the heap in bytes.

The reserve argument specifies the total heap allocation in virtual memory. The default heap size is 1 MB. The linker rounds up the specified value to the nearest 4 bytes.

The optional commit argument is subject to interpretation by the operating system. In Windows NT, it specifies the amount of physical memory to allocate at a time. Committed virtual memory causes space to be reserved in the paging file. A higher commit value saves time when the application needs more heap space but increases the memory requirements and possibly the startup time.

Specify the reserve and commit values in decimal or C-language notation.


/IMPLIB (Name Import Library)

Home | Overview | How Do I | Linker Options

Syntax

/IMPLIB:filename

This option overrides the default name for the import library that LINK creates when it builds a program that contains exports. The default name is formed from the base name of the main output file and the extension .LIB. A program contains exports if one or more of the following are specified:

  • The __declspec(dllexport) keyword in the source code

  • An EXPORTS statement in a .DEF file

  • An /EXPORT specification in a LINK command

LINK ignores /IMPLIB when an import library is not being created. If no exports are specified, LINK does not create an import library. If an export file is used in the build, LINK assumes that an import library already exists and does not create one. For information on import libraries and export files, see LIB Reference.


/IMPORT

Home | Overview | How Do I | Linker Options

Syntax

/IMPORT:[symbol][,][LIB=container][,WEAK=1]

/IMPORT:[CURRENTVER=#][,][OLDCODEVER=#][,][OLDAPIVER=#]

The /IMPORT option is specific for MACOS. You can use it to specify a function to be imported from a shared library or to specify compatible version numbers for a shared library.

Use the following syntax to import a shared library:

/IMPORT:[function][,][LIB=container][,WEAK=1]

In this syntax, function represents the name of the function you want to import and container represents the name of the library that contains the function.

By default, the functions and shared libraries must be present when the executable file loads. However, if you use the WEAK=1 qualifier with the /IMPORT option, a function or shared library need not be present when the executable file loads. You can make the function1 function in the CONT.LIB library weakly imported by typing the following:

/IMPORT:function1,LIB=CONT.LIB,WEAK=1

You can make the shared library CONT.LIB weakly imported by typing this:

/IMPORT:LIB=CONT.LIB,WEAK=1

You can use the following syntax to specify version numbers for a shared library:

/IMPORT: [CURRENTVER=#][,][OLDCODEVER=#][,][OLDAPIVER=#]

Set CURRENTVER to the current version number of the library. Set OLDCODEVER to the oldest version of the library whose code is compatible with the current definition or API. Set OLDAPIVER to the oldest version of the library that has a definition or API compatible with the current code. To set the current version to 5, the oldest code version to 4, and the oldest API version to 2, type the following:

/IMPORT:CURRENTVER=5,OLDCODEVER=4,OLDAPIVER=2


/INCLUDE (Force Symbol References)

Home | Overview | How Do I | Linker Options

The Force Symbol References (/INCLUDE:symbol) option tells the linker to add a specified symbol to the symbol table. (To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Input in the Category box.)

Type a symbol name in the Force Symbol References text box. To specify multiple symbols, type a comma (,), a semicolon (;), or a space between the symbol names. On the command line, specify /INCLUDE:symbol once for each symbol.

The linker resolves symbol by adding the object that contains the symbol definition to the program. This feature is useful for including a library object that otherwise would not be linked to the program.

Specifying a symbol with this option overrides the removal of that symbol by /OPT:REF.


/INCREMENTAL (Link Incrementally)

Home | Overview | How Do I | Linker Options

The Link Incrementally (/INCREMENTAL:{YES|NO}) option controls how the linker handles incremental linking. (To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Customize in the Category box.)

By default, the linker runs in incremental mode. To override a default incremental link, clear the Link Incrementally check box (or specify /INCREMENTAL:NO on the command line).

An incrementally linked program is functionally equivalent to a program that is nonincrementally linked. However, because it is prepared for subsequent incremental links, an incrementally linked executable (.EXE) file or dynamic-link library (DLL):

  • Is larger than a nonincrementally linked program because of padding of code and data. (Padding allows the linker to increase the size of functions and data without recreating the .EXE file.)

  • May contain jump thunks to handle relocation of functions to new addresses.

Note To ensure that your final release build does not contain padding or thunks, link your program nonincrementally.

To link incrementally regardless of the default, select the Link Incrementally check box (or specify /INCREMENTAL:YES on the command line). When this option is selected, the linker issues a warning if it cannot link incrementally, and then links the program nonincrementally. Certain options and situations override the Link Incrementally (/INCREMENTAL:YES) option.

Most programs can be linked incrementally. However, some changes are too great, and some options are incompatible with incremental linking. LINK performs a full link if any of the following options are specified:

  • Link Incrementally is not selected (/INCREMENTAL:NO).

  • COFF Format (/DEBUGTYPE:COFF) is selected.

  • Both Formats (/DEBUGTYPE:BOTH) is selected.

  • /OPT:REF is selected.

  • /OPT:ICF is selected.

  • /ORDER is selected.

  • Use Program Database is not selected (/PDB:NONE) when Generate Debug Info (/DEBUG) is selected.

Additionally, LINK performs a full link if any of the following situations occur:

  • The incremental status (.ILK) file is missing. (LINK creates a new .ILK file in preparation for subsequent incremental linking.)

  • There is no write permission for the .ILK file. (LINK ignores the .ILK file and links nonincrementally.)

  • The .EXE or .DLL output file is missing.

  • The timestamp of the .ILK, .EXE, or .DLL is changed.

  • A LINK option is changed. Most LINK options, when changed between builds, cause a full link.

  • An object (.OBJ) file is added or omitted.

  • An object that was compiled with the /Yu /Z7 option is changed.


/LARGEADDRESSAWARE

Home | Overview | How Do I | Linker Options

Syntax

/LARGEADDRESSWARE

Tells the linker that the application can handle addresses larger than 2 gigabytes.


/LIBPATH (Additional Libpath)

Home | Overview | How Do I | Linker Options

Syntax

/LIBPATH:dir

Use this linker option to override the environment library path. The linker will first search in the path specified by this option, and then search in the path specified in the LIB environment variable. You can specify only one directory for each /LIBPATH option you enter. If you want to specify more than one directory, you must specify multiple /LIBPATH options. The linker will then search the specified directories in order.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Input in the Category box.


/LINK50COMPAT (Backward Compatibility)

Home | Overview | How Do I | Linker Options

Syntax

/LINK50COMPAT

Tells the linker to generate import libraries in the old (Visual C++ version 5.0) format for backward compatibility.


/MACHINE (Specify Target Platform)

Home | Overview | How Do I | Linker Options

Syntax

/MACHINE:{IX86|MIPS|ALPHA|ARM|MIPS|MIPSR41XX|PPC|SH3|SH4}

This option specifies the target platform for the program.

Usually, you do not need to specify the /MACHINE option. LINK infers the machine type from the .OBJ files. However, in some circumstances LINK cannot determine the machine type and issues a linker tools error LNK1113. If such an error occurs, specify /MACHINE.


/MAP (Generate Mapfile)

Home | Overview | How Do I | Linker Options

This option tells the linker to create a mapfile.

Command Line | Project Settings | Description
/MAP | Generate Mapfile | The linker names the mapfile with the base name of the program and the extension .MAP.
/MAP:filename | Mapfile Name | This option overrides the default name for a mapfile.

A mapfile is a text file that contains the following information about the program being linked:

  • The module name, which is the base name of the file

  • The timestamp from the program file header (not from the file system)

  • A list of groups in the program, with each group’s start address (as section:offset), length, group name, and class

  • A list of public symbols, with each address (as section:offset), symbol name, flat address, and .OBJ file where the symbol is defined

  • The entry point (as section:offset)

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Debug in the Category box.

The /MAPINFO option specifies additional information to be included in the map file.


/MAPINFO (Include Information in Mapfile)

Home | Overview | How Do I | Linker Options

Syntax

/MAPINFO:{EXPORTS|FIXUPS|LINES}

This option tells the linker to include the specified information in a map file, which is created if you specify the /MAP option.

  • EXPORTS tells the linker to include exported functions.

  • FIXUPS tells the linker to include base-relocation information in the mapfile if relocation information exists in the image. Base relocations will be present in the image if you link with /FIXED:NO.

  • LINES includes line-number information.


/MERGE (Combine Sections)

Home | Overview | How Do I | Linker Options

Syntax

/MERGE:from=to

This option combines the first section (from) with the second section (to), naming the resulting section to. If the second section does not exist, LINK renames the section from as to.

The /MERGE option is useful for creating VxDs and overriding the compiler-generated section names.


/NODEFAULTLIB (Ignore Libraries)

Home | Overview | How Do I | Linker Options

Syntax

/NODEFAULTLIB[:library]

This option tells the linker to remove one or more default libraries from the list of libraries it searches when resolving external references.

Command Line | Project Settings | Description
/NODEFAULTLIB:library | Ignore Libraries | This option removes the specified library or libraries from the list of libraries it searches when resolving external references.
/NODEFAULTLIB | Ignore All Default Libraries | This option removes all default libraries from the list of libraries it searches when resolving external references.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Input in the Category box.

The linker resolves references to external definitions by searching first in libraries specified in the Object/Library Modules text box in the Project Settings dialog box (or on the command line), then in default libraries specified with the /DEFAULTLIB option, and then in default libraries named in .OBJ files.

To specify multiple libraries, type a comma (,) between the library names.

The Ignore Libraries (/NODEFAULTLIB:library) option overrides /DEFAULTLIB: library when the same library name is specified in both.


/NOENTRY (No Entry Point)

Home | Overview | How Do I | Linker Options

Syntax

/NOENTRY

This option is required for creating a resource-only DLL.

Use this option to prevent LINK from linking a reference to _main into the DLL.


/NOLOGO (Suppress Startup Banner)

Home | Overview | How Do I | Linker Options

This option prevents display of the copyright message and version number.

The Suppress Startup Banner option also suppresses echoing of command files. For details, see LINK Command Files.

By default, this information is sent by the linker to the Output window. On the command line, it is sent to standard output and can be redirected to a file.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Customize in the Category box.


Object/Library Modules

Home | Overview | How Do I | Linker Options

To pass an object file or standard library (either static or import) to the linker, specify the file name in the Object/Library Modules text box, or type the file name on the command line. You can specify an absolute or relative path with the file name, and you can use wildcards in the file name. If you omit the dot (.) and file name extension, the linker assumes .OBJ for the purpose of finding the file. The linker does not use file name extensions or the lack of them to make assumptions about the contents of files; it determines the type of file by examining it and processes it accordingly.

For additional information, see LINK Input Files.


/OPT (Optimizations)

Home | Overview | How Do I | Linker Options

Syntax

/OPT:{REF|NOREF|ICF[,iterations]|NOICF}

This option controls the optimizations that LINK performs during a build. Optimizations generally decrease the image size and increase the program speed, at a cost of increased link time.

  • Use /OPT:REF to eliminate functions and/or data that is never referenced.

  • Use /OPT:NOREF to keep functions and/or data that is never referenced.

  • Use /OPT:ICF[,iterations] to perform identical COMDAT folding. Redundant COMDATs can be removed from the linker output. Iterations specifies the number of times to traverse the symbols for duplicates. The default number of iterations is two. Additional iterations may locate more duplicates uncovered through folding in the previous iteration.

By default, LINK removes unreferenced packaged functions. An object contains packaged functions (COMDATs) if it has been compiled with the /Gy option. This optimization is called transitive COMDAT elimination. To override this default and keep unreferenced COMDATs in the program, specify /OPT:NOREF. You can use the /INCLUDE option to override the removal of a specific symbol.

If /OPT:REF is specified, /OPT:ICF is on by default. If you want /OPT:REF but not /OPT:ICF, you must specify the following:

link /opt:ref /opt:noicf

Specifying /OPT:ICF does not turn on the /OPT:REF option.

If the /DEBUG option is specified, the default for /OPT changes from REF to NOREF, and all functions are preserved in the image. To override this default and optimize a debugging build, specify /OPT:REF. The /OPT:REF option disables incremental linking.


/ORDER (Put Functions in Order)

Home | Overview | How Do I | Linker Options

Syntax

/ORDER:@filename

This option tells LINK to optimize your program by placing certain COMDATs into the image in a predetermined order. LINK places the functions in the specified order within each section in the image.

Specify the order in filename, which is a text file that lists the COMDATs in the order you want to link them. Each line in filename contains the name of one COMDAT. An object contains COMDATs if it has been compiled with the /Gy option. Function names are case sensitive.

LINK uses decorated forms of identifiers. The compiler decorates an identifier when it creates the .OBJ file. If the name of the COMDAT is specified to the linker in its undecorated form (as it appears in the source code), LINK attempts to match the name. If it cannot find a unique match, LINK issues an error message. Use the DUMPBIN tool to get the decorated form of an identifier when you need to specify it to the linker. For more information on decorated names, see Decorated Names.

Note Do not specify the decorated form of C identifiers that are declared __cdecl or __stdcall.

If more than one /ORDER specification is used, the last one specified takes effect.

Ordering allows you to optimize your program’s paging behavior through swap tuning by grouping a function with the functions it calls. You can also group frequently called functions together. These techniques increase the probability that a called function is in memory when it is needed and will not have to be paged from disk.

The /ORDER option disables incremental linking.

Note LINK cannot order static functions because static function names are not public symbol names. When /ORDER is specified, linker warning LNK4037 is generated for each symbol, in the order file, that is either static or not found.


/OUT (Output File Name)

Home | Overview | How Do I | Linker Options

The Output File Name (/OUT:filename) option overrides the default name and location of the program that the linker creates. (To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Customize in the Category box.)

By default, the linker forms the file name using the base name of the first .OBJ file specified and the appropriate extension (.EXE or .DLL).

The Output File Name option controls the default base name for a .MAP file or import library. For details, see Generate Mapfile (/MAP) and /IMPLIB.


/PDB (Use Program Database)

Home | Overview | How Do I | Linker Options

By default, when the Generate Debug Info (/DEBUG) option is specified, the linker creates a program database (PDB), which holds debugging information. If Generate Debug Info (/DEBUG) is not specified, the Use Program Database (/PDB) option is ignored.

Command Line | Project Settings | Description
/PDB:filename | Use Program Database, Program Database Name | The linker creates a program database file with the given file name.
/PDB:NONE | Use Program Database not selected | The linker does not create a PDB, but instead puts old-style debugging information into the .EXE file or DLL. The linker then calls the CVPACK.EXE tool, which must be in the same directory as LINK.EXE or in a directory in the PATH environment variable.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Customize in the Category box.

The default file name for the PDB has the base name of the program and the extension .PDB. To override the default name, type a file name in the Program Database Name text box, or specify /PDB:filename on the command line.

Debugging information in a PDB must be in Microsoft Format (/DEBUGTYPE:CV).

Incremental linking is suppressed if the Use Program Database check box is not selected (or if /PDB:NONE is specified on the command line).


/PDBTYPE (Program Database Storage)

Home | Overview | How Do I | Linker Options

Syntax

/PDBTYPE:{CON[SOLIDATE]|SEPT[YPES]}

Use this linker option to control in which Program Database (PDB) to store the debug type information.

On the command line, the /PDBTYPE option can take one of the following arguments:

  • Use /PDBTYPE:CON[SOLIDATE] to tell the linker to place the debug type information in a single .PDB file. This option is the default. This option cannot be used if /PDB:NONE is specified.

  • Use /PDBTYPE:SEPT[YPES] to tell the linker to leave the debug type information distributed in the source (compiler) .PDB files. In the Project Settings dialog box, select Separate Types in the Debug category of the Link tab to specify this linker option.

If SEPT[YPES] is specified, linking can be significantly faster. The advantages are:

  • The debugger startup time may be slightly faster.

  • Less hard disk space is needed to store data.

The disadvantage is more files are needed for the debugger to find the debug information when debugging.

Use this option when you plan to debug privately. Do not use this option when the debug build is to be used by multiple users.


/PROFILE (Enable Profiling)

Home | Overview | How Do I | Linker Options

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Enable Profiling option creates an output file that can be used with the profiler. A profiler-ready program has a map (.MAP) file. If it contains debugging information, the information must be stored in the output file instead of in a program database (.PDB) file and must be in Microsoft Format. This option also tells LINK to generate a relocation section in the program.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click General in the Category box. Selecting the Enable Profiling check box enables the Generate Mapfile (/MAP) option in the General and Debug categories. If you select the Generate Debug Info check box, be sure to select the Microsoft Format option button under Debug Info in the Debug category.

On the command line, /PROFILE has the same effect as setting the /MAP option; if the /DEBUG option is specified, then /PROFILE also implies the options /DEBUGTYPE:CV and /PDB:NONE. In either case, /PROFILE implies /INCREMENTAL:NO and /FIXED:NO.


/RELEASE (Set the Checksum)

Home | Overview | How Do I | Linker Options

This option sets the checksum in the header of an .EXE file.

The operating system requires the checksum for certain files, such as device drivers. It is recommended that you set the checksum for release versions of your programs to ensure compatibility with future operating systems.

The /RELEASE option is set by default when the /SUBSYSTEM:NATIVE option is specified.


/SECTION (Specify Section Attributes)

Home | Overview | How Do I | Linker Options

Syntax

/SECTION:name,[E][C][I][R][W][S][D][K][L][P][X]

This option changes the attributes of a section, overriding the attributes set when the .OBJ file for the section was compiled.

A section in a portable executable (PE) file is roughly equivalent to a segment or the resources in an NE file. Sections contain either code or data. Unlike segments, sections are blocks of contiguous memory with no size constraints. Some sections contain code or data that your program declared and uses directly, while other data sections are created for you by the linker and librarian, and contain information vital to the operating system.

Specify a colon (:) and a section name. The name is case sensitive.

Specify one or more attributes for the section. The attribute characters, listed below, are not case sensitive. You must specify all attributes that you want the section to have; an omitted attribute character causes that attribute bit to be turned off. The meanings of the attribute characters are shown below.

Character | Attribute | Meaning
E | Execute | Allows code to be executed
C | Conforming | Marks the section as conforming
I | IOPL | Marks the section as IOPL
R | Read | Allows read operations on data
W | Write | Allows write operations on data
S | Shared | Shares the section among all processes that load the image
D | Discardable | Marks the section as discardable
K | Cacheable | Marks the section as not cacheable
L | Preload | VxD only; marks the section as preload
P | Pageable | Marks the section as not pageable
X | Memory-resident | VxD only; marks the section as memory-resident

A section that does not have E, R, or W set is probably invalid.


/STACK (Stack Allocations)

Home | Overview | How Do I | Linker Options

The Stack Allocations (/STACK:reserve[,commit]) option sets the size of the stack in bytes.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Output in the Category box. The Reserve text box (or in the reserve argument on the command line) specifies the total stack allocation in virtual memory. The default stack size is 1 MB. The linker rounds up the specified value to the nearest 4 bytes.

The optional value specified in the Commit text box (or in the commit argument on the command line) is subject to interpretation by the operating system. In Windows NT, it specifies the amount of physical memory to allocate at a time. Committed virtual memory causes space to be reserved in the paging file. A higher commit value saves time when the application needs more stack space, but increases the memory requirements and possibly the startup time.

Specify the reserve and commit values in decimal or C-language notation.

Another way to set the size of the stack is with the STACKSIZE statement in a module-definition (.DEF) file. STACKSIZE overrides the Stack Allocations (/STACK) option if both are specified. You can change the stack after the .EXE file is built by using the EDITBIN tool.


/STUB (MS-DOS Stub File Name)

Home | Overview | How Do I | Linker Options

The MS-DOS Stub File Name (/STUB:filename) option attaches an MS-DOS stub program to a Win32 program.

A stub program is invoked if the file is executed in MS-DOS. It usually displays an appropriate message; however, any valid MS-DOS application can be a stub program.

Specify a filename for the stub program after a colon (:) on the command line. The linker checks filename to be sure that it is a valid MS-DOS executable file, and issues an error message if the file is not valid. The program must be an .EXE file; a .COM file is invalid for a stub program.

If this option is not used, the linker attaches a default stub program that issues the following message:

This program cannot be run in MS-DOS mode.


/SUBSYSTEM (Specify Subsystem)

Home | Overview | How Do I | Linker Options

Syntax

/SUBSYSTEM:{CONSOLE|WINDOWS|NATIVE|POSIX|WINDOWSCE}[,major[.minor]]

This option tells the operating system how to run the .EXE file. The subsystem is specified as follows:

  • The CONSOLE subsystem is for a Win32 character-mode application. Console applications are given a console by the operating system. If main or wmain is defined, CONSOLE is the default.

  • The WINDOWS subsystem applies to an application that does not require a console, probably because it creates its own windows for interaction with the user. Win32s operating systems can only run WINDOWS applications. If WinMain or wWinMain is defined, WINDOWS is the default.

  • The NATIVE subsystem applies device drivers for Windows NT.

  • The POSIX subsystem creates an application that runs with the POSIX subsystem in Windows NT.

The optional major and minor version numbers specify the minimum required version of the subsystem. The arguments are decimal numbers in the range 0 through 65,535. The default is version 4.00 for CONSOLE, WINDOWS, and NATIVE; and version 19.90 for POSIX.

The choice of subsystem affects the default starting address for the program. For more information, see the Entry-Point Symbol (/ENTRY:function) option.


/SWAPRUN (Load Linker Output to Swap File)

Home | Overview | How Do I | Linker Options

Syntax

/SWAPRUN:{NET|CD}

Tells the operating system to first copy the linker output to a swap file, and then run the image from there. This is a Windows NT 4.0 feature.

If NET is specified, the operating system will first copy the binary image from the network to a swap file and load it from there. This option is useful for running applications over the network. When CD is specified, the operating system will copy the image on a removable disk to a page file and then load it.


/VERBOSE (Print Progress Messages)

Home | Overview | How Do I | Linker Options

The linker sends information about the progress of the linking session to the Output window. On the command line, the information is sent to standard output and can be redirected to a file.

Command Line | Project Settings | Description
/VERBOSE | Print Progress Messages | Displays details about the linking process
/VERBOSE:LIB | Not applicable | Displays only progress messages indicating the libraries searched

The displayed information includes the library search process and lists each library and object name (with full path), the symbol being resolved from the library, and a list of objects that reference the symbol.

To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Customize in the Category box.


/VERSION (Version Information)

Home | Overview | How Do I | Linker Options

The Version Information (/VERSION:major[.minor]) option tells the linker to put a version number in the header of the .EXE file or DLL. (To find this option in the development environment, click Settings on the Project menu. Then click the Link tab, and click Output in the Category box.)

The major and minor arguments are decimal numbers in the range 0 through 65,535. The default is version 0.0.

Another way to insert a version number is with the VERSION module-definition statement.


/VXD (Create Virtual Device Driver)

Home | Overview | How Do I | Linker Options

This option creates a virtual device driver (VxD). When this option is specified, the default file name extension changes to .VXD. For details on VxDs, see the Microsoft Windows NT Device Driver Kit.

A .VXD file is not in Common Object File Format, and it cannot be used with DUMPBIN or EDITBIN. It does not contain debugging information. However, you can create a map file when you link a .VXD file.

A .VXD file cannot be incrementally linked.

For related information, see /EXETYPE.


/WARN (Warning Level)

Home | Overview | How Do I | Linker Options

Syntax

/WARN[:level]

With this option, you can determine the output of LINK warning messages. The level parameter takes the value 0, 1, 2, or 3. Currently, this option controls a limited subset of LINK warning messages. The greater the numeral used, the more messages may be generated.

Note Setting level to 0 does not disable warning messages.


/WS (Aggressively Trim Process Memory)

Home | Overview | How Do I | Linker Options

Syntax

/WS:AGGRESSIVE

Use this linker option to add the WS_AGGRESSIVE attribute to your application's image. The Windows NT 4.0 loader will recognize this attribute and aggressively trim the working set of the process when it is not active. Using this option is similar to adding the following call throughout your application.

SetProcessWorkingSetSize(hThisProcess, -1, -1)

/WS:AGGRESSIVE can be used for applications that must have a low impact on the system's memory pool.

If the speed of your application is important, do not use /WS:AGGRESSIVE without testing the resulting performance implications. Ideal candidates are processes that tend to operate in the background, such as services and screen savers.


BSCMAKE Reference

Home | Overviews | How Do I

The Microsoft Browse Information Maintenance Utility (BSCMAKE.EXE) builds a browse information file (.BSC) from .SBR files created during compilation. You view a browse information file in a browse window. For information about browse windows, see Class Browsing Tasks.

When you build your program, you can create a browse information file for your program automatically, using BSCMAKE to build the file. You do not need to know how to run BSCMAKE if you create your browse information file in the Visual C++ development environment. However, you may want to read this topic to understand the choices available.

If you build your program outside of the development environment, you can still create a custom .BSC that you can examine in the environment. Run BSCMAKE on the .SBR files that you created during compilation.

  • Building a .BSC file

  • BSCMAKE command line

  • BSCMAKE command file

  • BSCMAKE options

  • BSCMAKE exit codes


Building a .BSC File

Home | Overviews | How Do I

BSCMAKE can build a new browse information file from newly created .SBR files. It can also maintain an existing .BSC file using .SBR files for object files that have changed since the last build.

  • How to create an .SBR file

  • How BSCMAKE builds a .BSC file

  • How to increase BSCMAKE efficiency


Creating an .SBR File

Home | Overviews | How Do I

The input files for BSCMAKE are .SBR files. The compiler creates an .SBR file for each object file (.OBJ) it compiles. When you build or update your browse information file, all .SBR files for your project must be available on disk.

To create an .SBR file with all possible information, specify Generate Browse Info in the Project Settings dialog box (or /FR).

To create an .SBR file that doesn’t contain local symbols, specify Generate Browse Info, and then check Exclude Local Variables from Browse Info (/Fr on the compiler command line). If the .SBR files contain local symbols, you can still omit them from the .BSC file by using BSCMAKE’s /El option.

You can create an .SBR file without performing a full compile. For example, you can specify the /Zs option to the compiler to perform a syntax check and still generate an .SBR file if you specify /FR or /Fr.

The build process can be more efficient if the .SBR files are first packed to remove unreferenced definitions. The compiler automatically packs .SBR files. An unpacked .SBR file is required if you want to use the /Iu option with BSCMAKE to include unreferenced symbols in the .BSC file. If you want to prevent packing, specify /Zn on the compiler command line.


How BSCMAKE Builds a .BSC File

Home | Overviews | How Do I

BSCMAKE builds or rebuilds a .BSC file in the most efficient way it can. To avoid potential problems, it is important to understand the build process.

When BSCMAKE builds a browse information file, it truncates the .SBR files to zero length. During a subsequent build of the same file, a zero-length (or empty) .SBR file tells BSCMAKE that the .SBR file has no new contribution to make. It lets BSCMAKE know that an update of that part of the file is not required and an incremental build will be sufficient. During every build (unless the /n option is specified), BSCMAKE first attempts to update the file incrementally by using only those .SBR files that have changed.

BSCMAKE looks for a .BSC file that has the name specified with the /o option. If /o is not specified, BSCMAKE looks for a file that has the base name of the first .SBR file and a .BSC extension. If the file exists, BSCMAKE performs an incremental build of the browse information file using only the contributing .SBR files. If the file does not exist, BSCMAKE performs a full build using all .SBR files. The rules for builds are as follows:

  • For a full build to succeed, all specified .SBR files must exist and must not be truncated. If an .SBR file is truncated, you must rebuild it (by recompiling or assembling) before running BSCMAKE.

  • For an incremental build to succeed, the .BSC file must exist. All contributing .SBR files, even empty files, must exist and must be specified on the BSCMAKE command line. If you omit an .SBR file from the command line, BSCMAKE removes its contribution from the file.


BSCMAKE Command Line

Home | Overviews | How Do I

To run BSCMAKE, use the following command line syntax:

BSCMAKE [options] sbrfiles

Options can appear only in the options field on the command line.

The sbrfiles field specifies one or more .SBR files created by a compiler or assembler. Separate the names of .SBR files with spaces or tabs. You must specify the extension; there is no default. You can specify a path with the filename, and you can use operating-system wildcards (* and ?).

During an incremental build, you can specify new .SBR files that were not part of the original build. If you want all contributions to remain in the browse information file, you must specify all .SBR files (including truncated files) that were originally used to create the .BSC file. If you omit an .SBR file, that file’s contribution to the browse information file is removed.

Do not specify a truncated .SBR file for a full build. A full build requires contributions from all specified .SBR files. Before you perform a full build, recompile the project and create a new .SBR file for each empty file.

The following command runs BSCMAKE to build a file called MAIN.BSC from three .SBR files:

BSCMAKE main.sbr file1.sbr file2.sbr

For related information, see BSCMAKE Command File and BSCMAKE Options.


BSCMAKE Command File

Home | Overviews | How Do I

You can provide part or all of the command-line input in a command file. Specify the command file using the following syntax:

BSCMAKE @filename

Only one command file is allowed. You can specify a path with filename. Precede filename with an at sign (@). BSCMAKE does not assume an extension. You can specify additional sbrfiles on the command line after filename. The command file is a text file that contains the input to BSCMAKE in the same order as you would specify it on the command line. Separate the command-line arguments with one or more spaces, tabs, or newline characters.

The following command calls BSCMAKE using a command file:

BSCMAKE @prog1.txt

The following is a sample command file:

/n /v /o main.bsc /El
/S (
toolbox.h
verdate.h c:\src\inc\screen.h
)
file1.sbr file2.sbr file3.sbr file4.sbr


BSCMAKE Options

Home | Overviews | How Do I

This section describes the options available for controlling BSCMAKE. Several options control the content of the browse information file by excluding or including certain information. The exclusion options can allow BSCMAKE to run faster and may result in a smaller .BSC file. Option names are case sensitive (except for /HELP and /NOLOGO).

/Ei (filename...)

Excludes the contents of the specified include files from the browse information file. To specify multiple files, separate the names with a space and enclose the list in parentheses. Parentheses are not necessary if you specify only one filename. Use /Ei along with the /Es option to exclude files not excluded by /Es.

/El

Excludes local symbols. The default is to include local symbols. For more information about local symbols, see Creating an .SBR File.

/Em

Excludes symbols in the body of macros. Use /Em to include only the names of macros in the browse information file. The default is to include both the macro names and the result of the macro expansions.

/Er (symbol...)

Excludes the specified symbols from the browse information file. To specify multiple symbol names, separate the names with a space and enclose the list in parentheses. Parentheses are not necessary if you specify only one symbol.

/Es

Excludes from the browse information file every include file specified with an absolute path or found in an absolute path specified in the INCLUDE environment variable. (Usually, these are the system include files, which contain a lot of information that you may not need in your browse information file.) This option does not exclude files specified without a path or with relative paths or files found in a relative path in INCLUDE. You can use the /Ei option along with /Es to exclude files that /Es does not exclude. If you want to exclude only some of the files that /Es excludes, use /Ei instead of /Es and list the files you want to exclude.

/HELP

Displays a summary of the BSCMAKE command-line syntax.

/Iu

Includes unreferenced symbols. By default, BSCMAKE does not record any symbols that are defined but not referenced. If an .SBR file has been packed, this option has no effect for that input file because the compiler has already removed the unreferenced symbols.

/n

Forces a nonincremental build. Use /n to force a full build of the browse information file whether or not a .BSC file exists and to prevent .SBR files from being truncated. See How BSCMAKE Builds a .BSC File.

/NOLOGO

Suppresses the BSCMAKE copyright message.

/o filename

Specifies a name for the browse information file. By default, BSCMAKE gives the browse information file the base name of the first .SBR file and a .BSC extension.

/S (filename...)

Tells BSCMAKE to process the specified include file the first time it is encountered and to exclude it otherwise. Use this option to save processing time when a file (such as a header, or .H, file for a .C or .CPP source file) is included in several source files but is unchanged by preprocessing directives each time. You may also want to use this option if a file is changed in ways that are unimportant for the browse information file you are creating. To specify multiple files, separate the names with a space and enclose the list in parentheses. Parentheses are not necessary if you specify only one filename. If you want to exclude the file every time it is included, use the /Ei or /Es option.

/v

Provides verbose output, which includes the name of each .SBR file being processed and information about the complete BSCMAKE run.

/?

Displays a brief summary of BSCMAKE command-line syntax.

The following command line tells BSCMAKE to do a full build of MAIN.BSC from three .SBR files. It also tells BSCMAKE to exclude duplicate instances of TOOLBOX.H:

BSCMAKE /n /S toolbox.h /o main.bsc file1.sbr file2.sbr file3.sbr


BSCMAKE Exit Codes

Home | Overviews | How Do I

BSCMAKE returns an exit code (also called a return code or error code) to the operating system or the calling program.

Code | Meaning
0 | No error
1 | Command-line error
4 | Fatal error during build


Creating Precompiled Header Files

Home

The Microsoft C and C++ compilers provide options for precompiling any C or C++ code—including inline code. Using this performance feature, you can compile a stable body of code, store the compiled state of the code in a file, and during subsequent compilations combine the precompiled code with code that is still under development. Each subsequent compilation is faster because the stable code does not need to be recompiled.

Visual C++ offers two ways to create and use precompiled header files:

  • Use AppWizard and allow it to set default compiler options for your application.

  • Set compiler options yourself, either on the command line or in the development environment (Project menu, Settings command).

With Microsoft Visual C++, you can precompile any C or C++ code; you are not limited to precompiling only header files. To precompile headers, you can choose one of two approaches:

  • Automatic precompiling: Use just one option (/YX) and let the compiler decide when to create and use precompiled headers.

  • Manual precompiling: Use this when you know that your source files use common sets of header files but do not include them in the same order, or when you want to include source code in your precompilation.

The first choice is quick and easy. The second requires some planning, but it offers significantly faster compilations if you precompile source code other than simple header files.

What do you want to know more about?

  • When to precompile source code

  • Details on automatic and manual precompiling


When to Precompile Source Code

Home

Precompiled code is useful during the development cycle to reduce compilation time, especially if:

  • You always use a large body of code that changes infrequently.

  • Your program comprises multiple modules, all of which use a standard set of include files and the same compilation options. In this case, all include files can be precompiled into one precompiled header.

The first compilation—the one that creates the precompiled header file—takes a bit longer than subsequent compilations. Subsequent compilations can proceed more quickly by including the precompiled code.

You can precompile both C and C++ programs. In C++ programming, it is common practice to separate class interface information into header files. These header files can later be included in programs that use the class. By precompiling these headers, you can reduce the time a program takes to compile.

Note Although you can use only one precompiled header (.PCH) file per source file, you can use multiple .PCH files in a project.


Two Choices for Precompiling Code

Home

Either method of precompiling code—automatically or manually—stores the resulting precompiled code in a file called a precompiled header.

The easier way to precompile code is to use the automatic precompiled-header option (/YX). The /YX option causes the compiler to either create a precompiled header with a default name of MSVC.PCH or use a precompiled header named MSVC.PCH if one exists. You can also control the name of the precompiled header that is created or used with the /Fp (Specify Precompiled Header Filename) option.

The other way to precompile code is to use the manual precompiled-header options /Yc (Create Precompiled Header) and /Yu (Use Precompiled Header). Use the /Yc option to create a precompiled header. When used with the optional hdrstop pragma, /Yc lets you precompile both header files and source code. Use the /Yu option to use an existing precompiled header in the existing compilation. You can also use the /Fp option with the /Yc and /Yu options to provide an alternative name for the precompiled header.

The following sections describe the precompiled header options and #pragma hdrstop in more detail. See Using Precompiled Headers in a Project for a method for using PCH files; that section includes an example makefile and the code that it manages. For further examples using precompiled headers, see the makefiles used to build the program examples that ship with the Microsoft Foundation Class Library.


Precompiled Header Compiler Options

Home

The compiler options described in the following sections control the creation and use of precompiled headers. Using the hdrstop pragma gives you extra control over the behavior of these options.

  • /YX (Automate Precompiled Header) option

  • /Yc (Create Precompiled Header) option

  • /Yu (Use Precompiled Header) option

  • /Yd (Duplicate Debugging Information in All Object Files) option

  • /Fp (Specify Precompiled Header Filename) option


The /YX (Automate Precompiled Header) Option

Home

The /YX (Automate Precompiled Header) option instructs the compiler to use a precompiled header file with a default name of MSVC.PCH if it exists or to create one if it does not. The file is created in the current directory. You can use the /Fpfilename option to change the default name (and placement) of the precompiled header. The following command line uses /YX to create a precompiled header named MSVC.PCH:

CL /YX MYPROG.CPP

The following command line creates a precompiled header named MYPROG.PCH and places it in the \PROJPCH directory:

CL /YX /Fp\PROJPCH\MYPROG.PCH MYPROG.CPP

Using the /YX option limits precompilation to header files only. The precompiled header is created when the compiler encounters the first declaration, definition, hdrstop pragma, or #line directive that occurs in the source file. In a subsequent compilation, the precompiled header is used at the point in a source file where the compiler makes its final consistency check. For more information, see Consistency Rules for /YX.

The actual set of header files precompiled with /YX is determined by the compiler, which may use a subset of the header files available to make the resulting precompiled header useful in more cases.

Although it is usually best to let the compiler determine which header files to use, you can selectively precompile header files by placing a hdrstop pragma in the source file between two #include directives. All header files before the hdrstop pragma are precompiled; those after are not. When used with /YX, any filename specified with the hdrstop pragma is ignored. If any subsequent compilation using the precompiled header does not find an identical hdrstop pragma at the same point in the source file, the compiler builds a new precompiled header. For more information, see Using the hdrstop Pragma.

Note If either /Yc or /Yu is specified with /YX, a warning is issued. In such cases, /YX is ignored, and /Yc or /Yu takes precedence.

Use of the /YX option implies the /Yd (“duplicate debugging information in all object files”) option.


Debugging Code Compiled with /YX

Home

You can use either the /Zi or the /Z7 option with the /YX option to generate debugging information for CodeView or the integrated debugger.

It is recommended that you use the /Zi option unless you need /Z7 to maintain compatibility with Microsoft C/C++ version 7.0. The /Zi option places the generated debugging information into a program database (PDB); a PDB speeds linking during the debugging process. The /Yd option, which places all debugging information into every object file created using a precompiled header, is ignored unless used with /Z7.

The following table summarizes results obtained from using the /Zi, /Z7, and /Yd options in combination with /YX.

Results of Combining Debugging Options with /YX

Option | Result
/Zi | Debugging information for both the precompiled header and the rest of the source code is placed in a program database (PDB) with the default name of MSVC.PDB.
/Zi /Yd | /Yd is ignored. Debugging information for both the precompiled header and the rest of the source code is placed in a PDB with the default name of MSVC.PDB.
/Z7 | Debugging information for both the precompiled header and the rest of the source code is placed in every object file created using the precompiled header.
/Z7 /Yd | Debugging information for both the precompiled header and the rest of the source code is placed in every object file created using the precompiled header.

For more information on PDBs, see /Z7, /Zi, and /Fd. Also see The /Yd (Duplicate Debugging Information in All Object Files) Option.


Consistency Rules for /YX

Home

If a precompiled header file exists (either MSVC.PCH or one specified by /Fpfilename), it is compared to the current compilation for consistency. Unless the following requirements are met, a new precompiled header file is created and the new file overwrites the old:

  • The current compiler options must match those specified when the precompiled header was created.

  • The current working directory must match that specified when the precompiled header was created.

  • The order and values of all #include and #pragma directives must match those specified when the precompiled header was created. These, along with #define directives, are checked one by one as they appear during subsequent compilations that use the precompiled header. The values of #define directives must match. However, a sequence of #define directives need not occur in exactly the same order because there are no semantic order dependencies for #define directives. The #pragma directives must be nearly identical, with a few exceptions; for example, multiple spaces outside of strings are treated as a single space to allow for different programming styles.

  • The value and order of include paths specified on the command line with /I options must match those specified when the precompiled header was created.

  • The time stamps of all the header files (all files specified with #include directives) used to build the precompiled header must match those that existed when the precompiled header was created.


The /Yc (Create Precompiled Header) Option

Home

The /Yc (Create Precompiled Header) option instructs the compiler to create a precompiled header file that represents the state of compilation at a certain point. The syntax of this option is:

/Ycfilename

Using /Yc with a Filename

If you specify a filename with the /Yc option, the compiler precompiles all code up to and including the specified file. The precompiled code is saved in a file with a name created from the base name of the file specified with the /Yc option and a .PCH extension. You can also use the /Fp option, described in The /Fp (Specify Precompiled Header Filename) Option, to specify a name for the resulting precompiled header file.

Consider the following code:

#include <afxwin.h>   // Include header for class library
#include "resource.h" // Include resource definitions
#include "myapp.h"    // Include information specific to this
                      //   application
...

When compiled with the command

CL /YcMYAPP.H PROG.CPP

the compiler saves all the results of processing AFXWIN.H, RESOURCE.H, and MYAPP.H in a precompiled header file called MYAPP.PCH.

Using /Yc Without a Filename

If you specify the /Yc option with no filename, the resulting precompiled header saves the compilation state at the end of the base source file or, if the base file contains a hdrstop pragma, at the place where the hdrstop pragma occurs.

The resulting .PCH file has the same base name as your base source file unless you specify a different filename using the hdrstop pragma or the /Fp option.

Note If the /Ycfilename and /Yufilename options occur on the same command line and both reference the same filename, /Ycfilename takes precedence, precompiling all code up to and including the named file. This feature simplifies the writing of makefiles.


The /Yu (Use Precompiled Header) Option

Home

The /Yu (Use Precompiled Header) option instructs the compiler to use an existing precompiled header in the existing compilation. The syntax of this option is:

/Yufilename

Using /Yu with a Filename

The filename argument is the name of a header file, which is included in the source file using an #include preprocessor directive. The name of the include file must be the same for both the /Yc option that creates the precompiled header and any subsequent /Yu option indicating use of the precompiled header.

For /Yc, filename specifies the point at which precompilation stops; the compiler precompiles all code though filename and names the resulting precompiled header using the base name of the include file and an extension of .PCH. For /Yu, the compiler assumes that all code occurring before filename is precompiled. The compiler skips to the specified #include directive, uses the code contained in the precompiled header file, and then compiles all code after filename.

Consider the following code:

#include <afxwin.h>   // Include header for class library
#include "resource.h" // Include resource definitions
#include "myapp.h"    // Include information specific to this
                      //   application
...

When compiled with the command line

CL /YuMYAPP.H PROG.CPP

the compiler does not process the three #include statements but uses the precompiled code from the precompiled header MYAPP.PCH, thereby saving the time involved in preprocessing all three of the files (and any files they might include).

Using /Yu Without a Filename

When you specify the /Yu option without a filename, your source program must contain #pragma hdrstop. The compiler skips to the location of that pragma and uses the content of the precompiled header file specified by the pragma. If the hdrstop pragma does not specify a filename, the name is derived from the base name of the source file with the .PCH extension. You can also use the /Fp option to specify a different .PCH file.

If you specify the /Yu option without a filename and fail to specify a hdrstop pragma, an error message is generated and the compilation is unsuccessful.

Note If the /Ycfilename and /Yufilename options occur on the same command line and both reference the same filename, /Ycfilename takes precedence, precompiling all code up to and including the named file. This feature simplifies the writing of makefiles.


Debugging Code Compiled with /Yc or /Yu

Home

You can use either the /Zi or the /Z7 option with the /Yc and /Yu options to generate debugging information compatible with the Visual C++ debugger or CodeView.

It is recommended that you use the /Zi option unless you need /Z7 to maintain compatibility with Microsoft C/C++ version 7.0. The /Zi option places the generated debugging information into a program database (PDB); a PDB speeds linking during the debugging process. The /Yd option, which places all debugging information into every object file created using a precompiled header, is ignored unless used with /Z7.

The following table summarizes results obtained from using the /Zi, /Z7, and /Yd options in combination with /Yc and /Yu.

Results of Combining Debugging Options with /Yc or /Yu

Option | Result
/Zi | Debugging information for both the precompiled header and the rest of the source code is placed in a program database (PDB) with the default name of MSVC.PDB.
/Zi /Yd | /Yd is ignored. Debugging information for both the precompiled header and the rest of the source code is placed in a PDB with the default name of MSVC.PDB.
/Z7 | Debugging information for both the precompiled header and the rest of the source code is placed in the first object file created using the precompiled header.
/Z7 /Yd | Debugging information for both the precompiled header and the rest of the source code is placed in every object file created using the precompiled header.

For more information, see The /Yd (Duplicate Debugging Information in All Object Files) Option.


Consistency Rules for /Yc and /Yu

Home

When you use a precompiled header created using the /Yc option, the compiler compares the current compilation environment to the one that existed when you created the .PCH file. You should take care to specify a environment consistent with the previous one (using consistent compiler options, pragmas, and so on) for the current compilation. If the compiler detects an inconsistency, it issues a warning and identifies the inconsistency where possible. Such warnings don’t necessarily indicate a problem with the .PCH file; they simply warn you of possible conflicts. The following sections explain the consistency requirements for precompiled headers.

Compiler Option Consistency

Table 3 lists compiler options that might trigger an inconsistency warning when using a precompiled header.

Table 3 Compilation Option Consistency

Option | Name | Rule
/AX or /Axxx | Specify memory model | Must be the same between the compilation that created the precompiled header and the current compilation. If these options differ, a error message results.
/D | Define constants and macros | Must be the same between the compilation that created the precompiled header and the current compilation. The state of defined constants is not checked, but unpredictable results can occur if your files depend on the values of the changed constants.
/E or /EP | Copy preprocessor output to standard output | Precompiled headers do not work with the /E or /EP option.
/Fr or /FR | Generate Microsoft Source Browser information | For the /Fr and /FR options to be valid with the /Yu option, they must also have been in effect when the precompiled header was created. Subsequent compilations that use the precompiled header also generate Source Browser information. Browser information is placed in a single .SBR file and is referenced by other files in the same manner as CodeView information. You cannot override the placement of Source Browser information.
/GA, /GD, /GE,/Gw, or /GW | Windows protocol options | Must be the same between the compilation that created the precompiled header and the current compilation. If these options differ, a warning message results.
/Zi | Generate complete debugging information | If this option is in effect when the precompiled header is created, subsequent compilations that use the precompilation can use that debugging information. If /Zi is not in effect when the precompiled header is created, subsequent compilations that use the precompilation and the /Zi option trigger a warning. The debugging information is placed in the current object file, and local symbols defined in the precompiled header are not available to the debugger.

Note The precompiled header facility is intended for use only with a file that is a C or C++ program.

Include Path Consistency

A precompiled header created with /Yc does not contain information about the include path that was in effect when you created the .PCH file. When you use a .PCH file, the compiler always uses the include path specified in the current compilation.

Source File Consistency

When you use a precompiled header, the compiler ignores all preprocessor directives (including pragmas) that appear before the hdrstop pragma. The compilation specified by such preprocessor directives must be the same as the compilation used to create the precompiled header file.

Pragma Consistency

Pragmas processed during the compilation of a precompiled header usually affect the file in which the precompiled header is subsequently used. The following pragmas affect only the code within the .PCH file; they do not affect code that subsequently uses the .PCH file:

  • comment

  • linesize

  • message

  • page

  • pagesize

  • skip

  • subtitle

  • title

The following pragmas are retained as part of a precompiled header. They do affect the remainder of a compilation that uses the precompiled header:

  • alloc_text

  • auto_inline

  • check_pointer

  • check_stack

  • code_seg

  • data_seg

  • function

  • inline_depth

  • inline_recursion

  • intrinsic

  • loop_opt

  • native_caller

  • optimize

  • pack

  • same_seg

  • warning


The /Yd (Duplicate Debugging Information in All Object Files) Option

Home

Use the /Yd (Duplicate Debugging Information in All Object Files) option with the /Z7 (Generate Microsoft C/C++ Version 7.0 Compatible CodeView Information) option to place complete debugging information in all object files that are ultimately created from the resulting precompiled header (.PCH) file. The /Yd option takes no argument.

Note The /Yd option is obsolete with the advent of the new program database (PDB) files created by the “generate complete debugging information” (/Zi) option. The /Yd option is retained on /Zi, /Zd, and /Z7 for backward compatibility with Microsoft C/C++ version 7.0.

Storing complete debugging information in every object file, including the information that describes only the .PCH file, is sometimes convenient, but it slows compilation and requires considerable disk space.

In contrast, when /Yc and /Z7 are used without /Yd, the compiler stores debugging information describing the .PCH file in the first object file created from that file. The compiler does not insert this common debugging information into object files subsequently created from the .PCH file; rather, it inserts cross-references to the debugging information. Therefore, no matter how many object files use the .PCH file, only one object file contains the common debugging information.

Although this default behavior results in faster build times and reduces disk-space demands, it is undesirable if a small change requires rebuilding the object file containing the common debugging information. In this case, the compiler must rebuild all object files containing cross-references to the original object file. Also, it is difficult to rely on cross-references to a single object file if a common .PCH file is used by different projects.

Examples

Suppose you have two base files, F.CPP and G.CPP, each containing these #include statements:

#include "windows.h"
#include "etc.h"

The following command creates the precompiled header file ETC.PCH and the object file F.OBJ:

CL /YcETC.H /Z7 F.CPP

The object file F.OBJ includes type and symbol information for WINDOWS.H and ETC.H (and any other header files they include). Now you can use the precompiled header ETC.PCH to compile the source file G.CPP:

CL /YuETC.H /Z7 G.CPP

The object file G.OBJ does not include the debugging information for the precompiled header but simply references that information in the F.OBJ file. Note that you must link with the F.OBJ.

If your precompiled header was not compiled with /Z7, you can still use it in later compilations using /Z7. However, the debugging information is placed in the current object file, and local symbols for functions and types defined in the precompiled header are not available to the debugger.


The /Fp (Specify Precompiled Header Filename) Option

Home

The /Fp option gives you extra control over the name of the precompiled header (.PCH) file. Use it to specify a precompiled header filename that is different from the default. For example, use the following command to rename the default MSVC.PCH file created and used by the Automate Precompiled Header option:

CL /YX /FpMYPCH.PCH PROG.CPP

This command causes the compiler either to use a precompiled header named MYPCH.PCH if it exists or to create the file if it does not exist.

If you want to create a precompiled header file for a debugging version of your program and you are compiling both header files and source code, you can specify a command such as:

CL /DDEBUG /Zi /Yc /FpDPROG.PCH PROG.CPP

This command assumes the existence of a hdrstop pragma in PROG.CPP and creates a precompilation of all code up to the hdrstop pragma. The precompiled code is stored in a file called DPROG.PCH. If you need a release version in parallel, you simply change the compilation command to:

CL /Yc /FpRPROG.PCH PROG.CPP

This command creates a separate precompilation of all code up to the hdrstop pragma and stores it in RPROG.PCH.

You can also use the /Fp option with the /Yu and /YX options.


Using the hdrstop Pragma

Home

The hdrstop pragma gives you additional control over precompilation filenames and over the place at which the compilation state is saved. The syntax of the hdrstop pragma is

#pragma hdrstop ("filename")

where filename is the name of the precompiled header file to use or create (depending on whether /Yu or /Yc is specified). If the filename does not contain a path specification, the precompiled header file is assumed to be in the current directory. Any filename is ignored when the automatic precompiled header option (/YX) is specified.

Note The hdrstop pragma is ignored unless either the /YX option is specified or the /Yu or /Yc compiler option is specified without a filename.

For the /Yc and /Yu options, if neither of the two compilation options nor the hdrstop pragma specifies a filename, the base name of the source file is used as the base name of the precompiled header file. This differs from the precompiled-header naming conventions of /YX; with /YX, the default name of the precompiled header is MSVC.PCH.

The filename specified in the hdrstop pragma is a string and is therefore subject to the constraints of any C or C++ string. In particular, you must escape backslashes ( \ ) when specifying paths. For example:

#pragma hdrstop( "d:\\include\\myinc.pch" )

You can also use preprocessing commands to perform macro replacement as follows:

#define INCLUDE_PATH "c:\\progra~`1\\devstsu~1\\vc\\include\\"
#define PCH_FNAME "PROG.PCH"
.
.
.
#pragma hdrstop( INCLUDE_PATH PCH_FNAME )

See Placement of the hdrstop Pragma for more guidelines.


Placement of the hdrstop Pragma

Home

The following rules govern where the hdrstop pragma can be placed:

  • It must appear outside any data or function declaration or definition.

  • It must be specified in the base file, not within a header file.

Consider the following example:

#include <windows.h>                 // Include several files
#include "myhdr.h"

__inline Disp( char *szToDisplay )   // Define an inline function
{
    ...                              // Some code to display string
}
#pragma hdrstop

In this example, the hdrstop pragma appears after two files have been included and an inline function has been defined. This might, at first, seem to be an odd placement for the pragma. Consider, however, that using the manual precompilation options, /Yc and /Yu, with the hdrstop pragma makes it possible for you to precompile entire source files—even inline code. The Microsoft compiler does not limit you to precompiling only data declarations.


Using Precompiled Headers in a Project

Home

Previous sections present an overview of precompiled headers and reference material describing the manual precompiled-header options, /Yc and /Yu, the /Fp option, and the hdrstop pragma. This section describes a method for using the manual precompiled-header options in a project; it ends with an example makefile and the code that it manages.

For another approach to using the manual precompiled-header options in a project, study the makefile located in the \VC\MFC\SRC directory that is created during the default setup of Visual C++. The makefile takes a similar approach to the one presented in this section but makes greater use of Microsoft Program Maintenance Utility (NMAKE) macros to offer greater control of the build process.

Note The techniques presented in this section do not apply when using the Automate Precompiled Header option (/YX).


PCH Files in the Build Process

Home

The code base of a software project is usually contained in multiple C or C++ source files, object files, libraries, and header files. Typically, a makefile coordinates the combination of these elements into an executable file. Figure 1 shows the structure of a makefile that uses a precompiled header file. Both the NMAKE macro names and the filenames in this diagram coincide with those in the example code found at the end of this section.

The following figure uses three diagrammatic devices to show the flow of the build process. Named rectangles represent each file or each macro; the three macros represent one or more files. Shaded areas represent each compile or link action. Arrows show which files and macros are combined during the compilation or linking process.

Structure of a Makefile That Uses a Precompiled Header File

Beginning at the top of the diagram, both STABLEHDRS and BOUNDRY are NMAKE macros in which you list files not likely to need recompilation. These files are compiled using the command string

CL /c /W3 /Yc$(BOUNDRY) applib.cpp myapp.cpp

only if the precompiled header file (STABLE.PCH) does not exist or if you make changes to the files listed in the two macros. In either case, the precompiled header file will contain code only from the files listed in the STABLEHDRS macro. List the last file you want precompiled in the BOUNDRY macro.

The files you list in these macros can be either header files or C or C++ source files. (A single .PCH file cannot be used with both C and C++ modules.) Note that you can use the hdrstop macro to stop precompilation at some point within the BOUNDRY file. See Using the hdrstop Pragma for more information.

Continuing down the diagram, APPLIB.OBJ represents the support code used in your final application. It is created from APPLIB.CPP, the files listed in the UNSTABLEHDRS macro, and precompiled code from the precompiled header.

MYAPP.OBJ represents your final application. It is created from MYAPP.CPP, the files listed in the UNSTABLEHDRS macro, and precompiled code from the precompiled header.

Finally, the executable file (MYAPP.EXE) is created by linking the files listed in the OBJS macro (APPLIB.OBJ and MYAPP.OBJ).


Sample Makefile for PCH

Home

The following makefile uses macros and an !IF, !ELSE, !ENDIF flow-of-control command structure to simplify its adaptation to your project.

# Makefile : Illustrates the effective use of precompiled
#            headers in a project
# Usage:     NMAKE option
# option:    DEBUG=[0|1]
#            (DEBUG not defined is equivalent to DEBUG=0)
#
OBJS = myapp.obj applib.obj
# List all stable header files in the STABLEHDRS macro.
STABLEHDRS = stable.h another.h
# List the final header file to be precompiled here:
BOUNDRY = stable.h
# List header files under development here:
UNSTABLEHDRS = unstable.h
# List all compiler options common to both debug and final
# versions of your code here:
CLFLAGS = /c /W3
# List all linker options common to both debug and final
# versions of your code here:
LINKFLAGS = /NOD /ONERROR:NOEXE
!IF "$(DEBUG)" == "1"
CLFLAGS   = /D_DEBUG $(CLFLAGS) /Od /Zi /f
LINKFLAGS = $(LINKFLAGS) /COD
LIBS      = slibce
!ELSE
CLFLAGS   = $(CLFLAGS) /Oselg /Gs
LINKFLAGS = $(LINKFLAGS)
LIBS      = slibce
!ENDIF
myapp.exe: $(OBJS)
    link $(LINKFLAGS) @<<
$(OBJS), myapp, NUL, $(LIBS), NUL;
<<
# Compile myapp
myapp.obj  : myapp.cpp $(UNSTABLEHDRS)  stable.pch
    $(CPP) $(CLFLAGS) /Yu$(BOUNDRY)    myapp.cpp
# Compile applib
applib.obj : applib.cpp $(UNSTABLEHDRS) stable.pch
    $(CPP) $(CLFLAGS) /Yu$(BOUNDRY)    applib.cpp
# Compile headers
stable.pch : $(STABLEHDRS)
    $(CPP) $(CLFLAGS) /Yc$(BOUNDRY)    applib.cpp myapp.cpp

Besides the STABLEHDRS, BOUNDRY, and UNSTABLEHDRS macros shown in Figure 1, this makefile provides a CLFLAGS macro and a LINKFLAGS macro. You must use these macros to list compiler and linker options that apply whether you build a debug or final version of the application’s executable file. There is also a LIBS macro where you list the libraries that your project requires.

The makefile also uses !IF, !ELSE, !ENDIF to detect whether you define a DEBUG symbol on the NMAKE command line:

NMAKE DEBUG=[1|0]

This feature makes it possible for you to use the same makefile during development and for the final versions of your program—use DEBUG=0 for the final versions. The following command lines are equivalent:

NMAKE
NMAKE DEBUG=0

For more information on makefiles, see NMAKE Reference. Also see the Compiler Reference and the Linker Reference.


Example Code for PCH

Home

The following examples are used in the makefile described previously. Note that the comments contain important information.

// ANOTHER.H : Contains the interface to code that is not
//             likely to change.
//
#ifndef --ANOTHER_H
#define --ANOTHER_H
#include<iostream.h>
void savemoretime( void );
#endif // --ANOTHER_H

// STABLE.H : Contains the interface to code that is not likely
//            to change. List code that is likely to change
//            in the makefile's UNSTABLEHDR macro.
//
#ifndef --STABLE_H
#define --STABLE_H
#include<iostream.h>
void savetime( void );
#endif // --STABLE_H

// UNSTABLE.H : Contains the interface to code that is
//              likely to change. As the code in a header
//              file becomes stable, remove the header file
//              from the makefile's UNSTABLEHDR macro and list
//              it in the STABLEHDR macro.
//
#ifndef --UNSTABLE_H
#define --UNSTABLE_H
#include<iostream.h>
void notstable( void );
#endif // --UNSTABLE_H

// APPLIB.CPP : This file contains the code that implements
//              the interface code declared in the header
//              files STABLE.H, ANOTHER.H, and UNSTABLE.H.
//
#include"another.h"
#include"stable.h"
#include"unstable.h"
// The following code represents code that is deemed stable and
// not likely to change. The associated interface code is
// precompiled. In this example, the header files STABLE.H and
// ANOTHER.H are precompiled.
void savetime( void )
    { cout << "Why recompile stable code?\n"; }
void savemoretime( void )
    { cout << "Why, indeed?\n\n"; }
// The following code represents code that is still under
// development. The associated header file is not precompiled.
void notstable( void )
    { cout << "Unstable code requires"
            << " frequent recompilation.\n"; }

// MYAPP.CPP : Sample application
//             All precompiled code other than the file listed
//             in the makefile's BOUNDRY macro (stable.h in
//             this example) must be included before the file
//             listed in the BOUNDRY macro. Unstable code must
//             be included after the precompiled code.
//
#include"another.h"
#include"stable.h"
#include"unstable.h"
void main( void )
{
    savetime();
    savemoretime();
    notstable();
}


Optimization Articles

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Optimization-related articles are as follows:

  • IEEE Floating-Point Representation and Microsoft Languages

  • Why Floating Point Numbers May Lose Precision

  • Different Warnings Appear Using Different Optimizations

  • Using Function Name Without "()" Produces No Code


IEEE Floating-Point Representation and Microsoft Languages

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Microsoft Visual C++ is consistent with the IEEE numeric standards. There are three internal varieties of real numbers. Real*4 and real*8 are used in Visual C++. Real*4 is declared using the word float. Real*8 is declared using the word double. In Windows 32-bit programming, the long double data type maps to double. There is, however, assembly language support for computations using the real*10 data type.

The values are stored as follows:

Value | Stored as
real*4 | sign bit, 8-bit exponent, 23-bit mantissa
real*8 | sign bit, 11-bit exponent, 52-bit mantissa
real*10 | sign bit, 15-bit exponent, 64-bit mantissa

In real*4 and real*8 formats, there is an assumed leading 1 in the mantissa that is not stored in memory, so the mantissas are actually 24 or 53 bits, even though only 23 or 52 bits are stored. The real*10 format actually stores this bit.

The exponents are biased by half of their possible value. This means you subtract this bias from the stored exponent to get the actual exponent. If the stored exponent is less than the bias, it is actually a negative exponent.

The exponents are biased as follows:

Exponent | Biased by
8-bit (real*4) | 127
11-bit (real*8) | 1023
15-bit (real*10) | 16383

These exponents are not powers of ten; they are powers of two. That is, 8-bit stored exponents can be up to 127. The value 2**127 is roughly equivalent to 10**38, which is the actual limit of real*4.

The mantissa is stored as a binary fraction of the form 1.XXX... . This fraction has a value greater than or equal to 1 and less than 2. Note that real numbers are always stored in normalized form; that is, the mantissa is left-shifted such that the high-order bit of the mantissa is always 1. Because this bit is always 1, it is assumed (not stored) in the real*4 and real*8 formats. The binary (not decimal) point is assumed to be just to the right of the leading 1.

The format, then, for the various sizes is as follows:

 | BYTE 1 | BYTE 2 | BYTE 3 | BYTE 4 | ... | BYTE n
real*4 | XXXX XXXX | XMMM MMMM | MMMM MMMM | MMMM MMMM |  |
real*8 | SXXX XXXX | XXXX MMMM | MMMM MMMM | MMMM MMMM | ... | MMMM MMMM
real*10 | SXXX XXXX | XXXX XXXX | 1MMM MMMM | MMMM MMMM | ... | MMMM MMMM

S represents the sign bit, the X's are the exponent bits, and the M's are the mantissa bits. Note that the leftmost bit is assumed in real*4 and real*8 formats, but present as "1" in BYTE 3 of the real*10 format.

To shift the binary point properly, you first un-bias the exponent and then move the binary point to the right or left the appropriate number of bits.

The following are some examples in real*4 format:

                    SXXX XXXX XMMM MMMM ... MMMM MMMM
2   =  1  * 2**1  = 0100 0000 0000 0000 ... 0000 0000 = 4000 0000

Note the sign bit is zero, and the stored exponent is 128, or 100 0000 0 in binary, which is 127 plus 1. The stored mantissa is (1.) 000 0000 ... 0000 0000, which has an implied leading 1 and binary point, so the actual mantissa is one.

-2  = -1  * 2**1  = 1100 0000 0000 0000 ... 0000 0000 = C000 0000

Same as +2 except that the sign bit is set. This is true for all IEEE format floating-point numbers.

 4  =  1  * 2**2  = 0100 0000 1000 0000 ... 0000 0000 = 4080 0000

Same mantissa, exponent increases by one (biased value is 129, or 100 0000 1 in binary.

6  = 1.5 * 2**2  = 0100 0000 1100 0000 ... 0000 0000 = 40C0 0000

Same exponent, mantissa is larger by half—it's (1.) 100 0000 ...0000 0000, which, since this is a binary fraction, is 1 1/2 (the values of the fractional digits are 1/2, 1/4, 1/8, and so forth).

1  = 1   * 2**0  = 0011 1111 1000 0000 ... 0000 0000 = 3F80 0000

Same exponent as other powers of two, mantissa is one less than two at 127, or 011 1111 1 in binary.

.75 = 1.5 * 2**-1 = 0011 1111 0100 0000 ... 0000 0000 = 3F40 0000

The biased exponent is 126, 011 1111 0 in binary, and the mantissa is (1.) 100 0000 ... 0000 0000, which is 1 1/2.

2.5 = 1.25 * 2**1 = 0100 0000 0010 0000 ... 0000 0000 = 4020 0000

Exactly the same as two except that the bit that represents 1/4 is set in the mantissa.

0.1 = 1.6 * 2**-4 = 0011 1101 1100 1100 ... 1100 1101 = 3DCC CCCD

1/10 is a repeating fraction in binary. The mantissa is just shy of 1.6, and the biased exponent says that 1.6 is to be divided by 16 (it is 011 1101 1 in binary, which is 123 in decimal). The true exponent is 123 – 127 = –4, which means that the factor by which to multiply is 2**–4 = 1/16. Note that the stored mantissa is rounded up in the last bit—an attempt to represent the unrepresentable number as accurately as possible. (The reason that 1/10 and 1/100 are not exactly representable in binary is similar to the reason that 1/3 is not exactly representable in decimal.)

0  = 1.0 * 2**-128 = all zero's--a special case.


Why Floating Point Numbers May Lose Precision

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Floating point decimal values generally do not have an exact binary representation. This is a side effect of how the CPU represents floating point data. For this reason, you may experience some loss of precision, and some floating point operations may produce unexpected results.

This behavior is the result of one of the following:

  • The binary representation of the decimal number may not be exact.

  • There is a type mismatch between the numbers used (for example, mixing float and double).

To resolve the behavior, most programmers either ensure that the value is greater or less than what is needed, or they get and use a Binary Coded Decimal (BCD) library that will maintain the precision.

Microsoft uses IEEE floating point format for floating point number representation. For information about the actual binary representation of floating point values in a CPU and how precision and accuracy are affected in a floating point calculation, see IEEE Floating-Point Representation and Microsoft Languages.

Sample

/* Compile options needed: none. Value of c is printed with a decimal point precision of 10 and  6 (printf rounded value by default) to show the difference
*/
#include <stdio.h>
#define EPSILON 0.0001   // Define your own tolerance
#define FLOAT_EQ(x,v) (((v - EPSILON) < x) && (x <( v + EPSILON)))
void main()
{
    float a,b,c
    a=1.345f;
    b=1.123f;
    c=a+b;
   //if (FLOAT_EQ(c, 2.468))        // Remove comment for correct result
   if (c == 2.468)                 //Comment this line for correct result
   printf("They are equal\n");
else
   printf("They are not equal!!The value of c is %13.10f,or %f",c,c);
}

The Output Result

They are not equal. The value of c is 2.4679999352 or 2.468000.

For EPSILON, you may use the constants FLT_EPSILON defined for float as 1.192092896e-07F or DBL_EPSILON defined for double as 2.2204460492503131e-016. You need to include float.h for these constants. These constants are defined as the smallest positive number x, such that x+1.0 is not equal to 1.0. Because this is a very small number it is advisable that you employ user-defined tolerance for calculations involving very large numbers. See Floating Limits for other predefined constants.


Different Warnings Appear Using Different Optimizations

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

In the Microsoft C/C++ compiler, different warning messages can appear during separate compilations of the same code when different optimizations are used. This is normal behavior that occurs because some warnings are found only while optimizing.


Using Function Name Without "()" Produces No Code

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

When a function name declared in your program is used without parentheses, the compiler does not produce any code. The compiler may not produce error messages or warnings as long as the function has been prototyped. This occurs regardless of whether or not the function takes parameters because the compiler calculates the function address; however, because the function call operator "()" is not present, no call is made. This result is similar to the following:

   int a;
   a;      /* no code generated here either */

In Microsoft 32-bit Visual C++ , even using warning level 4 generates no diagnostic output. No warning is issued; no code is produced.

The sample code below compiles and links correctly without errors but produces no code in reference to funcn( ). For this to work correctly, add the function call operator "()".

#include <stdio.h>

void funcn();

void main( void )   {
   funcn;      /* missing function call operator;
                  call will fail.  Use funcn() */
   }

void funcn()
{
   printf("\nHello World\n");
}


LIB Reference

Home | Overviews

The Microsoft® 32-Bit Library Manager (LIB.EXE) creates and manages a library of Common Object File Format (COFF) object files. LIB can also be used to create export files and import libraries to reference exported definitions.

  • Overview of LIB

  • Running LIB

  • Managing a Library

  • Extracting a Library Member

  • Working with Import Libraries and Export Files


Overview of LIB

Home | Overviews

LIB creates standard libraries, import libraries, and export files that you can use with LINK when building a 32-bit program. LIB runs from a command prompt.

You can use LIB in the following modes:

  • Building or modifying a COFF library

  • Extracting a member object to a file

  • Creating an export file and an import library

These modes are mutually exclusive; you can use LIB in only one mode at a time.


LIB Input Files

Home | Overviews

The input files expected by LIB depend on the mode in which it is being used, as shown in the following table.

Mode | Input
Default (building or modifying a library) | COFF object (.OBJ) files, COFF libraries (.LIB), 32-bit Object Model Format (OMF) object (.OBJ) files
Extracting a member with /EXTRACT | COFF library (.LIB)
Building an export file and import library with /DEF | Module-definition (.DEF) file, COFF object (.OBJ) files, COFF libraries (.LIB), 32-bit OMF object (.OBJ) files

Note OMF libraries created by the 16-bit version of LIB cannot be used as input to the 32-bit version of LIB.


LIB Output Files

Home | Overviews

The output files produced by LIB depend on the mode in which it is being used, as shown in the following table.

Mode | Output
Default (building or modifying a library) | COFF library (.LIB)
Extracting a member with /EXTRACT | Object (.OBJ) file
Building an export file and import library with /DEF | Import library (.LIB) and export (.EXP) file


Other LIB Output

Home | Overviews

In the default mode, you can use the /LIST option to display information about the resulting library. You can redirect this output to a file.

LIB displays a copyright and version message and echoes command files unless the /NOLOGO option is used.

When you type lib with no other input, LIB displays a usage statement that summarizes its options.

Error and warning messages issued by LIB have the form LNKnnnn. The LINK, DUMPBIN, and EDITBIN tools also use this range of errors. Help for these errors is available by selecting the error in the Output window and pressing F1.


Structure of a Library

Home | Overviews

A library contains COFF objects. Objects in a library contain functions and data that can be referenced externally by other objects in a program. An object in a library is sometimes referred to as a library member.

You can get additional information about the contents of a library by running the DUMPBIN tool with the /LINKERMEMBER option. For more information about this option, see DUMPBIN Reference.


Running LIB

Home | Overviews

Various command-line options can be used to control LIB.

LIB Command Line

To run LIB, type the command lib followed by the options and filenames for the task you are using LIB to perform. LIB also accepts command-line input in command files, which are described in the following section. LIB does not use an environment variable.

Note If you are accustomed to the LINK32.EXE and LIB32.EXE tools provided with the Microsoft Win32 Software Development Kit for Windows NT, you may have been using either the command link32 -lib or the command lib32 for managing libraries and creating import libraries. Be sure to change your makefiles and batch files to use the lib command instead.

LIB Command Files

You can pass command-line arguments to LIB in a command file by using the following syntax:

LIB @commandfile

The file commandfile is a text file. No space or tab is allowed between the at sign (@) and the filename. There is no default extension; you must specify the full filename, including any extension. Wildcards cannot be used. You can specify an absolute or relative path with the filename.

In the command file, arguments can be separated by spaces or tabs, as they can on the command line; they can also be separated by newline characters. Use a semicolon (;) to mark a comment. LIB ignores all text from the semicolon to the end of the line.

You can specify either all or part of the command line in a command file, and you can use more than one command file in a LIB command. LIB accepts the command-file input as if it were specified in that location on the command line. Command files cannot be nested. LIB echoes the contents of command files unless the /NOLOGO option is used.

Using LIB Options

An option consists of an option specifier, which is either a dash ( – ) or a forward slash ( / ), followed by the name of the option. Option names cannot be abbreviated. Some options take an argument, specified after a colon (:). No spaces or tabs are allowed within an option specification. Use one or more spaces or tabs to separate option specifications on the command line. Option names and their keyword or filename arguments are not case sensitive, but identifiers used as arguments are case sensitive. LIB processes options in the order specified on the command line and in command files. If an option is repeated with different arguments, the last one to be processed takes precedence.

The following options apply to all modes of LIB:

/MACHINE:{IX86|ALPHA|ARM|MIPS|MIPSR41XX|PPC|SH3|SH4}

Specifies the target platform for the program. Usually, you do not need to specify /MACHINE. LIB infers the machine type from the .OBJ files. However, in some circumstances, LIB cannot determine the machine type and issues an error message. If such an error occurs, specify /MACHINE. In /EXTRACT mode, this option is for verification only.

/NOLOGO

Suppresses display of the LIB copyright message and version number and prevents echoing of command files.

/VERBOSE

Displays details about the progress of the session. The information is sent to standard output and can be redirected to a file.

Other options apply only to specific modes of LIB. These options are discussed in the sections describing each mode.


Managing a Library

Home | Overviews

The default mode for LIB is to build or modify a library of COFF objects. LIB runs in this mode when you do not specify /EXTRACT (to copy an object to a file) or /DEF (to build an import library).

To build a library from objects and/or libraries, use the following syntax:

LIB [options...] files...

This command creates a library from one or more input files. The files can be COFF object files, 32-bit OMF object files, or existing COFF libraries. LIB creates one library that contains all objects in the specified files. If an input file is a 32-bit OMF object file, LIB converts it to COFF before building the library. LIB cannot accept a 32-bit OMF object that is in a library created by the 16-bit version of LIB. You must first use the 16-bit LIB to extract the object; then you can use the extracted object file as input to the 32-bit LIB.

By default, LIB names the output file using the base name of the first object or library file and the extension .LIB. The output file is put in the current directory. If a file already exists with the same name, the output file replaces the existing file. To preserve an existing library, use the /OUT option to specify a name for the output file.

The following options apply to building and modifying a library:

/LIST

Displays information about the output library to standard output. The output can be redirected to a file. You can use /LIST to determine the contents of an existing library without modifying it.

/OUT:filename

Overrides the default output filename. By default, the output library is created in the current directory, with the base name of the first library or object file on the command line and the extension .LIB.

/LIBPATH:dir

Overrides the environment library path. For details, see the description of the LINK /LIBPATH option.

/LINK50COMPAT

Generates an import library in the previous (Visual C++ version 5.0) format for backwards compatibility.

/CONVERT

Converts an import library to the previous (Visual C++ version 5.0) format.

/REMOVE:object

Omits the specified object from the output library. LIB creates an output library by first combining all objects (whether in object files or libraries), and then deleting any objects specified with /REMOVE.

/SUBSYSTEM:{NATIVE|WINDOWS|CONSOLE|WINDOWSCE|POSIX}[,left[.right]]

Tells the operating system how to run a program created by linking to the output library. For more information, see the description of the LINK /SUBSYSTEM option.

You can use LIB to perform the following library-management tasks:

  • To add objects to a library, specify the filename for the existing library and the filenames for the new objects.

  • To combine libraries, specify the library filenames. You can add objects and combine libraries with a single LIB command.

  • To replace a library member with a new object, specify the library containing the member object to be replaced and the filename for the new object (or the library that contains it). When an object that has the same name exists in more than one input file, LIB puts the last object specified in the LIB command into the output library. When you replace a library member, be sure to specify the new object or library after the library that contains the old object.

  • To delete a member from a library, use the /REMOVE option. LIB processes any specifications of /REMOVE after combining all input objects, regardless of command-line order.

Note You cannot both delete a member and extract it to a file in the same step. You must first extract the member object using /EXTRACT, then run LIB again using /REMOVE. This behavior differs from that of the 16-bit LIB (for OMF libraries) provided in other Microsoft products.


Extracting a Library Member

Home | Overviews

You can use LIB to create an object (.OBJ) file that contains a copy of a member of an existing library. To extract a copy of a member, use the following syntax:

LIB library /EXTRACT:member /OUT:objectfile

This command creates an .OBJ file called objectfile that contains a copy of a member of a library. The member name is case sensitive. You can extract only one member in a single command. The /OUT option is required; there is no default output name. If a file called objectfile already exists in the specified directory (or the current directory, if no directory is specified with objectfile), the extracted objectfile replaces the existing file.


Working with Import Libraries and Export Files

Home | Overviews

You can use LIB with the /DEF option to create an import library and an export file. LINK uses the export file to build a program that contains exports (usually a dynamic-link library (DLL)), and it uses the import library to resolve references to those exports in other programs.

In most situations, you do not need to use LIB to create your import library. When you link a program (either an executable file or a DLL) that contains exports, LINK automatically creates an import library that describes the exports. Later, when you link a program that references those exports, you specify the import library.

However, when a DLL exports to a program that it also imports from, whether directly or indirectly, you must use LIB to create one of the import libraries. When LIB creates an import library, it also creates an export file. You must use the export file when linking one of the DLLs.


Building an Import Library and Export File

Home | Overviews

To build an import library and export file, use the following syntax:

LIB /DEF[:deffile] [options] [objfiles] [libraries]

When /DEF is specified, LIB creates the output files from export specifications that are passed in the LIB command. There are three methods for specifying exports, listed in recommended order of use:

  1. A __declspec(dllexport) definition in one of the objfiles or libraries

  2. A specification of /EXPORT:name on the LIB command line

  3. A definition in an EXPORTS statement in a deffile

These are the same methods you use to specify exports when linking an exporting program. A program can use more than one method. You can specify parts of the LIB command (such as multiple objfiles or /EXPORT specifications) in a command file in the LIB command, just as you can in a LINK command.

The following options apply to building an import library and export file:

/DEBUGTYPE:{CV|COFF|BOTH}

Sets the format of debugging information. Specify CV for Microsoft Symbolic Debugging Information, required by Visual C++. Specify COFF for Common Object File Format debugging information used by some other debuggers. Specify BOTH for both COFF debugging information and Microsoft format debugging information.

/OUT:import

Overrides the default output filename for the import library being created. When /OUT is not specified, the default name is the base name of the first object file or library in the LIB command and the extension .LIB. The export file is given the same base name as the import library and the extension .EXP.

/EXPORT:entryname[=internalname][,@ordinal[,NONAME]][,DATA]

Exports a function from your program to allow other programs to call the function. You can also export data (using the DATA keyword). Exports are usually defined in a DLL.

The entryname is the name of the function or data item as it is to be used by the calling program. Optionally, you can specify the internalname as the function known in the defining program; by default, internalname is the same as entryname. The ordinal specifies an index into the export table in the range 1 through 65,535; if you do not specify ordinal, LIB assigns one. The NONAME keyword exports the function only as an ordinal, without an entryname. The DATA keyword is used to export data-only objects.

/INCLUDE:symbol

Adds the specified symbol to the symbol table. This option is useful for forcing the use of a library object that otherwise would not be included.


Using an Import Library and Export File

Home | Overviews

When a program (either an executable file or a DLL) exports to another program that it also imports from, or if more than two programs both export to and import from each other, the commands to link these programs must accommodate circular exports.

In a situation without circular exports, when you link a program that uses exports from another program, you must specify the import library for the exporting program. The import library for the exporting program is created when you link that exporting program. Therefore, you must link the exporting program before the importing program. For example, if TWO.DLL imports from ONE.DLL, you must first link ONE.DLL and get the import library ONE.LIB. You then specify ONE.LIB when you link TWO.DLL. When the linker creates TWO.DLL, it also creates its import library, TWO.LIB. You use TWO.LIB when linking programs that import from TWO.DLL.

However, in a circular export situation, it is not possible to link all of the interdependent programs using import libraries from the other programs. In the example discussed earlier, if TWO.DLL also exports to ONE.DLL, the import library for TWO.DLL won’t exist yet when ONE.DLL is linked. When circular exports exist, you must use LIB to create an import library and export file for one of the programs.

To begin, choose one of the programs on which to run LIB. In the LIB command, list all objects and libraries for the program and specify /DEF. If the program uses a .DEF file or /EXPORT specifications, specify these as well.

After you create the import library (.LIB) and the export file (.EXP) for the program, you use the import library when linking the other program or programs. LINK creates an import library for each exporting program it builds. For example, if you run LIB on the objects and exports for ONE.DLL, you create ONE.LIB and ONE.EXP. You can now use ONE.LIB when linking TWO.DLL; this step also creates the import library TWO.LIB.

Finally, link the program you began with. In the LINK command, specify the objects and libraries for the program, the .EXP file that LIB created for the program, and the import library or libraries for the exports used by the program. To continue the example, the LINK command for ONE.DLL contains ONE.EXP and TWO.LIB, as well as the objects and libraries that go into ONE.DLL. Do not specify the .DEF file or /EXPORT specifications in the LINK command; these are not needed, because the export definitions are contained in the .EXP file. When you link using an .EXP file, LINK does not create an import library, because it assumes that one was created when the .EXP file was created.


Module-Definition (.DEF) Files

Home | Overview | FAQ | Details

A module-definition (.DEF) file is a text file that contains statements for defining an .EXE file or DLL.

Because LINK provides equivalent command-line options for most module-definition statements, a typical program for Win32 does not usually require a .DEF file. The descriptions of the module-definition statements give the command-line equivalent for each statement.

See the following sections for more information:

  • Rules for Module-Definition Statements

  • NAME

  • LIBRARY

  • DESCRIPTION

  • STACKSIZE

  • SECTIONS

  • EXPORTS

  • VERSION


Rules for Module-Definition Statements

Home | Overview | FAQ | Details

The following syntax rules apply to all statements in a .DEF file. Other rules that apply to specific statements are described with each statement.

  • Statements and attribute keywords are not case sensitive. User-specified identifiers are case sensitive.

  • Long filenames containing spaces or semicolons (;) must be enclosed in quotation marks (").

  • Use one or more spaces, tabs, or newline characters to separate a statement keyword from its arguments and to separate statements from each other. A colon (:) or equal sign (=) that designates an argument is surrounded by zero or more spaces, tabs, or newline characters.

  • A NAME or LIBRARY statement, if used, must precede all other statements.

  • Most statements appear at most once in the .DEF file and accept one specification of arguments. The specification follows the statement keyword on the same or subsequent line(s). If the statement is repeated with different arguments later in the file, the later statement overrides the earlier one.

  • The SECTIONS, EXPORTS, and IMPORTS statements can appear more than once in the .DEF file. Each statement can take multiple specifications, which must be separated by one or more spaces, tabs, or newline characters. The statement keyword must appear once before the first specification and can be repeated before each additional specification.

  • Many statements have an equivalent LINK command-line option. See the description of the corresponding LINK option for additional details.

  • Comments in the .DEF file are designated by a semicolon (;) at the beginning of each comment line. A comment cannot share a line with a statement, but it can appear between specifications in a multiline statement. (SECTIONS and EXPORTS are multiline statements.)

  • Numeric arguments are specified in decimal or C-language notation.

  • If a string argument matches a reserved word, it must be enclosed in double quotation marks (").


NAME

Home | Overview | FAQ | Details

Syntax

NAME [application][BASE=address]

This statement specifies a name for the main output file. An equivalent way to specify an output filename is with the Output File Name (/OUT) option, and an equivalent way to set the base address is with the Base Address (/BASE) option. If both are specified, /OUT overrides NAME.


LIBRARY

Home | Overview | FAQ | Details

Syntax

LIBRARY [library][BASE=address]

This statement tells LINK to create a DLL. At the same time, LINK creates an import library, unless an .EXP file is used in the build.

The library argument specifies the internal name of the DLL. (Use the Output File Name (/OUT) option to specify the DLL’s output name.)

The BASE=address argument sets the base address that the operating system uses to load the DLL. This argument overrides the default DLL location of 0x10000000. See the description of the Base Address (/BASE) optionfor details about base addresses.

An equivalent way to specify a DLL build is with the /DLL option, and an equivalent way to set the base address is with the /BASE option.


DESCRIPTION

Home | Overview | FAQ | Details

Syntax

DESCRIPTION "text"

This statement writes a string into an .rdata section. Enclose the specified text in single or double quotation marks (' or "). To use a literal quotation mark (either single or double) in the string, enclose the string with the other type of mark.

This feature differs from the comment specified with the /COMMENT option.


STACKSIZE

Home | Overview | FAQ | Details

Syntax

STACKSIZE reserve[,commit]

This statement sets the size of the stack in bytes. An equivalent way to set the stack is with the Stack Allocations (/STACK) option. See the documentation on that option for details about the reserve and commit arguments.


SECTIONS

Home | Overview | FAQ | Details

Syntax

SECTIONS definitions

This statement sets attributes for one or more sections in the image file. It can be used to override the default attributes for each type of section.

SECTIONS marks the beginning of a list of section definitions. Each definition must be on a separate line. The SECTIONS keyword can be on the same line as the first definition or on a preceding line. The .DEF file can contain one or more SECTIONS statements. The SEGMENTS keyword is supported as a synonym for SECTIONS.

The syntax for a section definition is:

section [CLASS 'classname'] attributes

The section name is case sensitive. The CLASS keyword is supported for compatibility, but is ignored. The attributes are one or more of the following: EXECUTE, READ, SHARED, and WRITE.

An equivalent way to specify section attributes is with the /SECTION option.


EXPORTS

Home | Overview | FAQ | Details

Syntax

EXPORTS definitions

This statement makes one or more definitions available as exports to other programs.

EXPORTS marks the beginning of a list of export definitions. Each definition must be on a separate line. The EXPORTS keyword can be on the same line as the first definition or on a preceding line. The .DEF file can contain one or more EXPORTS statements.

The syntax for an export definition is:

entryname[=internalname] [@ordinal[NONAME]] [DATA] [PRIVATE]

The optional keyword PRIVATE prevents entryname from being placed in the import library generated by LINK. It has no effect on the export in the image also generated by LINK.

There are three methods for exporting a definition, listed in recommended order of use:

  1. The __declspec(dllexport) keyword in the source code

  2. An EXPORTS statement in a .DEF file

  3. An /EXPORT specification in a LINK command

All three methods can be used in the same program. When LINK builds a program that contains exports, it also creates an import library, unless an .EXP file is used in the build.


VERSION

Home | Overview | FAQ | Details

Syntax

VERSION major[.minor]

This statement tells LINK to put a number in the header of the .EXE file or DLL. The major and minor arguments are decimal numbers in the range 0 through 65,535. The default is version 0.0.

An equivalent way to specify a version number is with the Version Information (/VERSION) option.


EDITBIN Reference

Home | Overviews

The Microsoft COFF Binary File Editor (EDITBIN.EXE) modifies 32-bit Common Object File Format (COFF) binary files. You can use EDITBIN to modify object files, executable files, and dynamic-link libraries (DLLs).

Note EDITBIN runs only from the command line.

EDITBIN converts the format of an Object Module Format (OMF) input file to COFF before making other changes to the file. You can use EDITBIN to convert the format of a file to COFF by running EDITBIN with no options.

  • EDITBIN command line

  • EDITBIN options


EDITBIN Command Line

Home | Overviews

To run EDITBIN, use the following syntax:

EDITBIN [options] files...

Specify one or more files for the objects or images to be changed, and one or more options for changing the files.

When you type the command editbin without any other command-line input, EDITBIN displays a usage statement that summarizes its options.


EDITBIN Options

Home | Overviews

An option consists of an option specifier, which is either a dash ( – ) or a forward slash ( / ), followed by the name of the option. Option names cannot be abbreviated. Some options take arguments, specified after a colon ( : ). No spaces or tabs are allowed within an option specification. Use one or more spaces or tabs to separate option specifications on the command line. Option names and their keyword or filename arguments are not case sensitive.

EDITBIN has the following options:

  • /BIND

  • /HEAP

  • /LARGEADDRESSAWARE

  • /NOLOGO

  • /REBASE

  • /RELEASE

  • /SECTION

  • /STACK

  • /SUBSYSTEM

  • /SWAPRUN

  • /VERSION

  • /WS


/BIND

Home | Overviews

This option sets the addresses of the entry points in the import address table for an executable file or DLL. Use this option to reduce load time of a program.

/BIND[:PATH=path]

Specify the program’s executable file and DLLs in the files argument on the EDITBIN command line. The optional path argument to /BIND specifies the location of the DLLs used by the specified files. Separate multiple directories with a semicolon (;). If path is not specified, EDITBIN searches the directories specified in the PATH environment variable. If path is specified, EDITBIN ignores the PATH variable.

By default, the program loader sets the addresses of entry points when it loads a program. The amount of time this process takes varies, depending on the number of DLLs and the number of entry points referenced in the program. If a program has been modified with /BIND, and if the base addresses for the executable file and its DLLs do not conflict with DLLs that are already loaded, the operating system does not need to set these addresses. In a situation where the files are incorrectly based, the operating system relocates the program’s DLLs and recalculates the entry-point addresses, which adds to the program’s load time.


/HEAP

Home | Overviews

This option sets the size of the heap in bytes.

/HEAP:reserve[,commit]

The reserve argument specifies the total heap allocation in virtual memory. The default heap size is 1 MB. The linker rounds up the specified value to the nearest 4 bytes.

The optional commit argument is subject to interpretation by the operating system. In Windows NT and Windows 95, it specifies the amount of physical memory to allocate at a time. Committed virtual memory causes space to be reserved in the paging file. A higher commit value saves time when the application needs more heap space but increases the memory requirements and possibly the startup time.

Specify the reserve and commit values in decimal or C-language notation.


/LARGEADDRESSAWARE

Home | Overviews

This option edits the image to indicate that the application can handle addresses larger than 2 gigabytes.

/LARGEADDRESSWARE


/NOLOGO

Home | Overviews

This option suppresses display of the EDITBIN copyright message and version number.

/NOLOGO


/REBASE

Home | Overviews

This option sets the base addresses for the specified files. EDITBIN assigns new base addresses in a contiguous address space according to the size of each file rounded up to the nearest 64K. For details about base addresses, see the Base Address (/BASE) linker option.

/REBASE[:modifiers]

Specify the program’s executable files and DLLs in the files argument on the EDITBIN command line in the order in which they are to be based. You can optionally specify one or more modifiers, each separated by a comma (,):

Modifier | Action
BASE=address | Provides a beginning address for reassigning base addresses to the files. Specify address in decimal or C-language notation. If BASE is not specified, the default starting base address is 0x400000. If DOWN is used, BASE must be specified, and address sets the end of the range of base addresses.
BASEFILE | Creates a file named COFFBASE.TXT, which is a text file in the format expected by LINK’s /BASE option.
DOWN | Tells EDITBIN to reassign base addresses downward from an ending address. The files are reassigned in the order specified, with the first file located in the highest possible address below the end of the address range. BASE must be used with DOWN to ensure sufficient address space for basing the files. To determine the address space needed by the specified files, run EDITBIN with /REBASE on the files and add 64K to the displayed total size.


/RELEASE

Home | Overviews

This option sets the checksum in the header of an executable file.

/RELEASE

The operating system requires the checksum for certain files, such as device drivers. It is recommended that you set the checksum for release versions of your programs to ensure compatibility with future operating systems.


/SECTION

Home | Overviews

This option changes the attributes of a section, overriding the attributes that were set when the object file for the section was compiled or linked.

/SECTION:name[=newname][,attributes][,alignment]

After the colon ( : ), specify the name of the section. To change the section name, follow name with an equal sign (=) and a newname for the section.

To set or change the section’s attributes, specify a comma (,) followed by one or more attributes characters. To negate an attribute, precede its character with an exclamation point (!). The following characters specify memory attributes:

Attribute | Setting
c | code
d | discardable
e | executable
i | initialized data
k | cached virtual memory
m | link remove
o | link info
p | paged virtual memory
r | read
s | shared
u | uninitialized data
w | write

To control alignment, specify the character a followed by a character to set the size of alignment in bytes, as follows:

Character | Alignment size in bytes
1 | 1
2 | 2
4 | 4
8 | 8
p | 16
t | 32
s | 64
x | no alignment

Specify the attributes and alignment characters as a string with no white space. The characters are not case sensitive.


/STACK

Home | Overviews

This option sets the size of the stack in bytes and takes arguments in decimal or C-language notation. The /STACK option applies only to an executable file.

/STACK:reserve[,commit]

The reserve argument specifies the total stack allocation in virtual memory. EDITBIN rounds up the specified value to the nearest 4 bytes.

The optional commit argument is subject to interpretation by the operating system. In Windows NT and Windows 95, commit specifies the amount of physical memory to allocate at a time. Committed virtual memory causes space to be reserved in the paging file. A higher commit value saves time when the application needs more stack space but increases the memory requirements and possibly startup time.


/SUBSYSTEM

Home | Overviews

This option edits the image to indicate which subsystem the operating system must invoke for execution.

/SUBSYSTEM:{CONSOLE|WINDOWS|NATIVE|WINDOWSCE|POSIX|}[,left[,right]]

You can specify any of the following subsystems:

  • The CONSOLE subsystem handles a Win32 character-mode application that use a console supplied by the operating system.

  • The WINDOWS subsystem handles an application that does not require a console and creates its own windows, if required.

  • The NATIVE subsystem handles a Windows NT device driver.

  • The WINDOWSCE subsystem handles Windows CE consumer electronics applications.

  • The POSIX subsystem handles a POSIX application in Windows NT.

The optional left and right values specify the minimum required version of the specified subsystem. The whole number part of the version number (the portion to the left of the decimal point) is represented by left. The fractional part of the version number (the portion to the right of the decimal point) is represented by right. The values of left and right must be from 0 through 65,535. The default is version 4.00 for CONSOLE, WINDOWS, and NATIVE; and version 19.90 for POSIX.

The choice of subsystem affects the default starting address for the program. For more information, see the linker Entry-Point Symbol (/ENTRY:function) option.


/SWAPRUN

Home | Overviews

This option edits the image to tell the operating system to copy the image to a swap file and run it from there. Use this option for images that reside on networks or removable media.

/SWAPRUN:{[!]NET|[!]CD}

You can add or remove the NET or CD qualifiers:

  • NET indicates that the image resides on a network.

  • CD indicates that the image resides on a CD-ROM or similar removable medium.

  • Use !NET and !CD to reverse the effects of NET and CD.


/VERSION

Home | Overview | How Do I | Linker Options

This option places a version number into the header of the image.

/VERSION:left[,right]

The whole number part of the version number (the portion to the left of the decimal point) is represented by left. The fractional part of the version number (the portion to the right of the decimal point) is represented by right.


/WS

Home | Overview | How Do I | Linker Options

This option adds the WS_AGGRESSIVE attribute to your application's image.

/WS:AGGRESSIVE

In Windows NT 4.0 and later, the loader recognizes this attribute and aggressively trims the working set of the process when the process is inactive. This has the same effect as using the following call throughout your application.

SetProcessWorkingSetSize(hThisProcess, -1, -1)

Use /WS:AGGRESSIVE for applications such as services and screen savers that must have a low impact on the system's memory pool. If the speed of your application matters, do not use /WS:AGGRESSIVE without testing the resulting performance.


DUMPBIN Reference

Home | Overviews

The Microsoft COFF Binary File Dumper (DUMPBIN.EXE) displays information about 32-bit Common Object File Format (COFF) binary files. You can use DUMPBIN to examine COFF object files, standard libraries of COFF objects, executable files, and dynamic-link libraries (DLLs).

Note DUMPBIN runs only from the command line.

  • DUMPBIN command line

  • DUMPBIN options


DUMPBIN Command Line

Home | Overviews

To run DUMPBIN, use the following syntax:

DUMPBIN [options] files...

Specify one or more binary files, along with any options required to control the information. DUMPBIN displays the information to standard output. You can either redirect it to a file or use the /OUT option to specify a filename for the output.

When you run DUMPBIN on a file without specifying an option, DUMPBIN displays the /SUMMARY output.

When you type the command dumpbin without any other command-line input, DUMPBIN displays a usage statement that summarizes its options.


DUMPBIN Options

Home | Overviews

An option consists of an option specifier, which is either a dash ( – ) or a forward slash (/), followed by the name of the option. Option names cannot be abbreviated. Some options take arguments, specified after a colon (:). No spaces or tabs are allowed within an option specification. Use one or more spaces or tabs to separate option specifications on the command line. Option names and their keyword or filename arguments are not case sensitive. Most options apply to all binary files; a few apply only to certain types of files. By default, DUMPBIN sends information to standard output. Use the /OUT option to send output to a file.

DUMPBIN has the following options:

  • /ALL

  • /ARCH

  • /ARCHIVEMEMBERS

  • /DEPENDENTS

  • /DIRECTIVES

  • /DISASM

  • /EXPORTS

  • /FPO

  • /HEADERS

  • /IMPORTS

  • /LINENUMBERS

  • /LINKERMEMBER

  • /OUT

  • /PDATA

  • /RAWDATA

  • /RELOCATIONS

  • /SECTION

  • /SUMMARY

  • /SYMBOLS


/ALL

Home | Overviews

This option displays all available information except code disassembly. Use /DISASM to display disassembly. You can use /RAWDATA:NONE with /ALL to omit the raw binary details of the file.


/ARCH

Home | Overviews

This option dumps the .arch section of an image.


/ARCHIVEMEMBERS

Home | Overviews

This option displays minimal information about member objects in a library.


/DEPENDENTS

Home | Overviews

Dumps the names of the DLLs from which the image imports functions. Does not dump the names of the imported functions.


/DIRECTIVES

Home | Overviews

This option dumps the compiler-generated .drective section of an image.


/DISASM

Home | Overviews

This option displays disassembly of code sections, using symbols if present in the file.


/EXPORTS

Home | Overviews

This option displays all definitions exported from an executable file or DLL.


/FPO

Home | Overviews

This option displays frame pointer optimization (FPO) records.


/HEADERS

Home | Overviews

This option displays the file header and the header for each section. When used with a library, it displays the header for each member object.


/IMPORTS

Home | Overviews

This option displays all definitions imported to an executable file or DLL.

The output displayed by this option is similar to the /EXPORTS output.


/LINENUMBERS

Home | Overviews

This option displays COFF line numbers. Line numbers exist in an object file if it was compiled with Program Database (/Zi), C7 Compatible (/Z7), or Line Numbers Only (/Zd). An executable file or DLL contains COFF line numbers if it was linked with Generate Debug Info (/DEBUG) and COFF Format (/DEBUGTYPE:COFF).


/LINKERMEMBER

Home | Overviews

Syntax

/LINKERMEMBER[:{1|2}]

This option displays public symbols defined in a library. Specify the 1 argument to display symbols in object order, along with their offsets. Specify the 2 argument to display offsets and index numbers of objects, and then list the symbols in alphabetical order, along with the object index for each. To get both outputs, specify /LINKERMEMBER without the number argument.


/OUT

Home | Overviews

Syntax

/OUT:filename

This option specifies a filename for the output. By default, DUMPBIN displays the information to standard output.


/PDATA

Home | Overviews

This option dumps the exception tables (.pdata) from an image or object.


/RAWDATA

Home | Overviews

Syntax

/RAWDATA[:{BYTES|SHORTS|LONGS|NONE}[,number]]

This option displays the raw contents of each section in the file. The arguments control the format of the display, as shown below:

Argument | Result
BYTES | The default. Contents are displayed in hexadecimal bytes, and also as ASCII characters if they have a printed representation.
SHORTS | Contents are displayed in hexadecimal words.
LONGS | Contents are displayed in hexadecimal longwords.
NONE | Raw data is suppressed. This argument is useful to control the output of /ALL.
number | Displayed lines are set to a width that holds number values per line.


/RELOCATIONS

Home | Overviews

This option displays any relocations in the object or image.


/SECTION

Home | Overviews

Syntax

/SECTION:section

This option restricts the output to information on the specified section.


/SUMMARY

Home | Overviews

This option displays minimal information about sections, including total size. This option is the default if no other option is specified.


/SYMBOLS

Home | Overviews

This option displays the COFF symbol table. Symbol tables exist in all object files. A COFF symbol table appears in an image file only if it is linked with the Generate Debug Info and COFF Format options under Debug Info on the Debug category for the linker (or the /DEBUG and /DEBUGTYPE:COFF options on the command line).


Decorated Names

Home | Overviews

Functions in C and C++ programs are known internally by their decorated names. A decorated name is a string created by the compiler during compilation of the function definition or prototype.

A decorated name is sometimes required when you specify a function name to LINK or other tools. For details about the situations that require decorated names, consult the documentation for the tool you are using.

Note The decorated naming convention for pointers to member functions was changed in Visual C++ version 4.0. C++ libraries created with Visual C++ version 2.0 should be recompiled to link properly with source files compiled with the current version of Visual C++.

To create or view decorated names, see:

  • Using Decorated Names

  • Viewing Decorated Names


Using Decorated Names

Home | Overviews

In most circumstances, you do not need to know the decorated name of a function. LINK and other tools can usually handle the name in its undecorated form.

However, certain situations require that you specify the name in its decorated form. You must specify the decorated name of C++ functions that are overloaded and special member functions, such as constructor and destructor functions, in order for LINK and other tools to be able to match the name. You must also use decorated names in assembly source files that reference a C or C++ function name.

Warning If you change the function name, class, calling convention, return type, or any parameter, the decorated name is no longer valid. You must get the new version of the function name and use it everywhere the decorated name is specified.


Format of a C++ Decorated Name

Home | Overviews

A decorated name for a C++ function contains the following information:

  • The function name.

  • The class that the function is a member of, if it is a member function. This may include the class that encloses the function’s class, and so on.

  • The namespace the function belongs to (if it is part of a namespace).

  • The types of the function’s parameters.

  • The calling convention.

  • The return type of the function.

The function and class names are encoded in the decorated name. The rest of the decorated name is a code that has internal meaning only for the compiler and the linker. The following are examples of undecorated and decorated C++ names.

Undecorated Name | Decorated Name
int a(char){int i=3;return i;}; | ?a@@YAHD@Z
void __stdcall b::c(float){}; | ?c@b@@AAGXM@Z


Format of a C Decorated Name

Home | Overviews

The form of decoration for a C function depends on the calling convention used in its declaration, as shown below.

Calling Convention | Decoration
__cdecl (the default) | Leading underscore (_)
__stdcall | Leading underscore (_) and a trailing at sign (@) followed by a number representing the number of bytes in the parameter list
__fastcall | Same as __stdcall, but prepended by an at sign instead of an underscore


Viewing Decorated Names

Home | Overviews

You can get the decorated form of a function name after you compile the source file that contains the function definition or prototype. To examine decorated names in your program, you can do one of the following:

  • Use a listing

  • Use the DUMPBIN tool


Using a Listing to View Decorated Names

Home | Overviews

To get the decorated form of a function using a compiler listing, do the following:

  1. Generate a listing by compiling the source file that contains the function definition or prototype with the Listing File Type (/FA[c|s]) compiler option set to one of the following three choices: Assembly with Machine Code (/FAc); Assembly with Source Code (/FAs); Assembly, Machine Code, and Source (/FAcs).

  2. Find the line that contains the undecorated function definition in the resulting listing.

  3. Examine the previous line. The label for the PROC NEAR command is the decorated form of the function name.


Using DUMPBIN to View Decorated Names

Home | Overviews

To get the decorated form of a function using DUMPBIN, run it on the .OBJ or .LIB file using the /SYMBOLS option. Find the undecorated function definition in the output. The undecorated name is followed by the decorated name, each enclosed in parentheses.


Faster Builds and Smaller Header Files

Home | Overviews

To speed the build process, Visual C++ provides the following defines that reduce the size of the Win32 header files.

  • VC_EXTRALEAN

  • WIN32_LEAN_AND_MEAN

Newly generated Visual C++ AppWizard applications automatically benefit from VC_EXTRALEAN. You can also manually define VC_EXTRALEAN to speed the build process of many legacy MFC applications.

Non-MFC C++ and C applications can define WIN32_LEAN_AND_MEAN and any applicable NOservice defines, such as NOSOUND (see ProgramFiles\Microsoft Visual Studio\VC98\include\Windows.h and ProgramFiles\Microsoft Visual Studio\VC98\MFC\Include\afxv_w32.h), to reduce their build times.

To add these defines, from the Project menu, choose Settings. The Projects settings dialog box appears. Click the C/C++ tab. In the Category list, select Preprocessor. Add the desired definitions to the Preprocessor Definitions box.

Knowledge Base article Q151666 also discusses these preprocessor definitions.


Adding User-Interface Features

After creating a starter project, usually with AppWizard, many developers like to "hook up" the user interface next. This involves designing and creating dialog boxes, menus, toolbars, accelerators, and other visual and interactive elements, then connecting them to code. This book covers a wide range of user-interface topics.
Overviews Short introductions to the concepts important in adding user-interface features to your program
How Do I Explanations of the tasks to perform as you add user-interface features
Frequently Asked Questions Focused questions that other Visual C++ users are asking too
Details Longer conceptual articles about the subjects you need at this stage
What else do you want to do?
See what user-interface features MFC supports.
Learn how to use ClassWizard.
Learn how to use the source code editor effectively.
Learn how to create new resources.

Interesting home pages
Visual C++ Home The entire Visual C++ product -- and your gateway to all of the documentation
Adding program functionality Home page for adding code "under the hood" -- the code that makes your program unique
Compiling and Linking Building your program so you can test it
Debugging Debugging your program


Adding User-Interface Features: Overviews

Home | How Do I | Details | FAQ

Why do we distinguish between program functionality and user-interface features?

What are Microsoft’s guidelines for user-interface design in Windows?

Does Visual C++ supply any “clip art” resources such as icons, cursors, toolbar buttons?

What do you want to know about?

Windows, Dialog Boxes, and Controls

  • Window Objects: Overview

  • Dialog Boxes: Overview

  • Property Sheets: Overview

  • Controls: Overview

  • ActiveX Controls: Overview

Control Bars: Toolbars, Status Bars, and Dialog Bars

  • Control Bars: Overview

  • Toolbars: Overview

  • Tool Tips: Overview

  • Status Bars: Overview

  • Dialog Bars: Overview

OLE and MFC Document/View Architecture

  • OLE: User-Interface Overview

  • Document/View: Overview

Other Overviews

  • Clipboard: Overview

  • Menus: Overview

  • Resource Editors: Overview

  • Printing and Print Preview: Overview

  • Help: Context-Sensitive Help Overview


Program Functionality Vs. User-Interface Features: Overview

Home | How Do I | Details | FAQ

Why distinguish between “program functionality” and “user-interface features”? Research suggests that most developers prefer to separate the following programming tasks:

  • Designing and “wiring up” a program’s user interface: its menus, toolbars, dialog boxes, windows, and other visible features with which end-users interact directly

  • Writing the less visible code that implements the program’s “engine”: the “under-the-hood” code that accomplishes what the program is all about, such as performing spreadsheet calculations or formatting word-processor text

Use the Adding User-Interface Features Home Page to locate topics related to programming user-interface features.

Use the Adding Program Functionality Home Page to locate topics related to implementing deeper program functionality.


The User Interface Guidelines for Microsoft Windows

Home | How Do I | Details | FAQ

Most first-class applications for the Microsoft Windows operating system share a familiar and consistent user interface. This improves the usability of the application because the user is not forced to relearn common operations. For example, a user who regularly prints documents from Microsoft Word intuitively looks for a Print option on the File menu when confronted with the task of printing in an unfamiliar application.

Microsoft suggests guidelines that help you use the standard Windows user interface objects and environment in a consistent manner. The book The Windows Interface: An Application Design Guide is available from Microsoft Press; it contains a chapter on overall principles and methodology along with specific guidelines for keyboard input, windows, menus, and so on.

The Microsoft Foundation Class Library (MFC), and especially the skeleton applications created with AppWizard, provide a good starting point to develop an application that conforms to the published guidelines. These tools ease the process of developing an application that has the “look and feel” expected by experienced users of the Windows environment.

MFC was designed to support the published user interface guidelines. Overriding the default behavior in derived classes tends to be more difficult than working with the default behavior of MFC. Adding to the default behavior is relatively simple.


COMMON.RES Sample Resources

Home | How Do I | Details | FAQ

Visual C++ includes sample resources that you can use in your own application. These include:

  • A large number of icons that represent common business and data-processing tasks.

  • Several commonly used cursors that are not included as predefined Windows resources.

  • A selection of toolbar-button bitmaps.

These resources are located in a file called COMMON.RES in the MFC General sample CLIPART. Additional sample resources (.rc files) can be found in the same directory on the MSDN compact disc that holds the Visual C++ samples.

To copy resources from COMMON.RES to your own resource script file

  1. Use the Visual C++ File menu to open both your .RC file and COMMON.RES at the same time.

  2. Hold down the CTRL key and drag the resources you want from the COMMON.RES resource browser window to the resource browser window of your own application.

For more information about browsing and editing resources with Visual C++, see Overview: Resource Editors, in the Visual C++ User’s Guide. And see Resource Editors: Overview for resource-editor topics specific to Visual C++.


ActiveX Controls: Overview

Home | How Do I | Details | Sample | Tutorial

ActiveX controls, formerly known as OLE controls, let you develop sophisticated controls based on the Common Object Model (COM) that can be installed in dialog boxes or any ActiveX control container application, including pages on the Internet’s World Wide Web and Visual Basic applications. Unlike Visual Basic (VBX) controls, ActiveX controls can be built in either 32-bit or 16-bit versions. With some work, you can convert existing VBXs to ActiveX controls.

An ActiveX control is an COM-based object that can draw itself in its own window, respond to events (such as mouse clicks), and be managed through an interface that includes properties and methods similar to those in Automation objects. The only limitation on the kinds of ActiveX controls you can create is your imagination.

These controls can be developed for many uses, such as database access, data monitoring, or graphing. Besides their portability, ActiveX controls support features previously not available to custom controls, such as compatibility with existing OLE containers and the ability to integrate their menus with the OLE container menus. In addition, an ActiveX control fully supports Automation, which allows the control to expose writable properties and a set of methods that can be called by the control user.

Beginning with MFC 4.2, you can create windowless ActiveX controls and controls that only create a window when they become active. Windowless controls speed up the display of your application and make it possible to have transparent and nonrectangular controls. With MFC versions 4.2 and later, you can also load ActiveX control properties asynchronously.

What do you want to do?

  • Learn more about ActiveX controls

  • Create an ActiveX control project with ControlWizard

  • Optimize an ActiveX control

  • Convert an existing VBX control to an ActiveX control

  • Convert an existing Control Development Kit (CDK) project to a Visual C++ project


Clipboard: Overview

Home | How Do I | Details

The Windows clipboard is used in two ways:

  • Implementing standard Edit menu commands, such as Cut, Copy, and Paste

  • Implementing uniform data transfer with drag and drop (OLE)

What do you want to know more about?

  • Implementing the standard Edit commands

  • The Win32 Clipboard API functions

  • The Clipboard in the Win32 SDK

  • Implementing drag and drop (OLE)

  • The clipboard’s role in drag and drop


Controls: Overview

Home | How Do I | Details | Sample

Controls are interactive objects that you place in dialog boxes or other windows to carry out user actions. The controls that you can use or create with Visual C++ include:

  • Windows common controls, including those introduced with Windows 95.

  • Additional controls available with MFC, such as bitmap buttons.

  • ActiveX controls that you create yourself or that you obtain from control suppliers.

  • Owner-drawn controls, for which you supply code for drawing the control and for interacting with it.

MFC supplies classes for manipulating Windows common controls, or you can use the Windows API functions for that purpose. The Visual C++ dialog editor lets you add these controls to your dialog boxes.

ActiveX controls are based on a programming model that lets you develop any sort of control you need, such as grid controls or data access controls. Based on the Common Object Model (COM), these controls are binary objects usable in any ActiveX control container, including pages on the Internet’s World Wide Web and containers developed with Visual C++ and Visual Basic.

What do you want to do?

  • Learn more about:
    • Windows common controls

    • ActiveX controls
  • Add common controls to a dialog box in a Visual C++ application

  • Program common controls: initialize them, modify their properties, extract data from them

  • Use MFC controls:
    • CBitmapButton

    • CCheckListBox

    • CDragListBox
  • Create an ActiveX control

  • Add an existing ActiveX control to a dialog box


Control Bars: Overview

Home | How Do I | Details | Sample

Control bars are windows that display rows of controls with which users can select options, execute commands, or obtain program information. Types of control bars include toolbars, dialog bars, and status bars. In MFC, the classes for these control-bar types are derived from a common base class, CControlBar.

What do you want to do?

  • Learn more about control bars in general

  • Learn more about:
    • Toolbars

    • Dialog bars

    • Status bars


Dialog Bars: Overview

Home | How Do I | Details | Sample

Dialog bars are control bars with both toolbar and dialog-box characteristics. They behave like toolbars, but because they are based on dialog templates, they can have any control that a dialog box can. MFC supports dialog bars with class CDialogBar.

What do you want to do?

  • Learn more about dialog bars

  • Create a dialog bar


Dialog Boxes: Overview

Home | How Do I | Details | Sample | Tutorial

Dialog boxes are windowsused to display status information or to obtain information from the user. The user uses dialog boxes to have a “dialog” with your program. Dialog boxes contain controls, including:

  • Windows common controls such as edit boxes, pushbuttons, list boxes, combo boxes, tree controls, list controls, and progress indicators.

  • ActiveX controls.

  • Owner-drawn controls: controls that you are responsible for drawing in the dialog box.

Most dialog boxes are modal. The user can interact only with the dialog box while the box is open. But it is possible to create modeless dialog boxes, which let users work with other windows while the dialog box is open. MFC supports both kinds of dialog box with class CDialog. The controls are arranged and managed using a dialog-template resource, created with the dialog editor.

Property sheets, also known as tab dialog boxes, are dialog boxes that contain “pages” of distinct dialog-box controls. Each page has a file folder “tab” at the top. Clicking on a tab brings that page to the front of the dialog box.

What do you want to do?

  • Learn more about:
    • Modal and modeless dialog boxes

    • Property sheet dialog boxes (tab dialog boxes)
  • Create a:
    • Modal dialog box

    • Modeless dialog box

    • Property sheet dialog box
  • Create a dialog-template resource with the dialog editor

  • Work with dialog boxes

  • Work with MFC’s dialog data exchange (DDX) and validation (DDV)


Document/View: Overview

Home | How Do I | Details | Sample | Tutorial

By default, MFC applications use a programming model that separates a program’s data from the display of that data and from most user interaction with the data. In this model, an MFC document object reads and writes data to persistent storage. The document may also provide an interface to the data wherever it resides (such as in a database). A separate view object manages data display, from rendering the data in a window to user selection and editing of data. The view obtains display data from the document and communicates back to the document any data changes.

While you can easily override or ignore the document/view separation, there are compelling reasons to follow this model in most cases. One of the best is when you need multiple views of the same document, such as both a spreadsheet and a chart view. The document/view model lets a separate view object represent each view of the data, while code common to all views (such as a calculation engine) can reside in the document. The document also takes on the task of updating all views whenever the data changes.

MFC’s document/view architecture makes it easy to support multiple views, multiple document types, splitter windows, and other valuable user-interface features. At the heart of document/view are four key classes:

  • CDocument (or COleDocument), an object used to store or control your program’s data.

  • CView (or one of its many derived classes), an object used to display a document’s data and manage user interaction with the data.

  • CFrameWnd (or one of its variations), an object that provides the frame around one or more views of a document.

  • CDocTemplate (or CSingleDocTemplate or CMultiDocTemplate), an object that coordinates one or more existing documents of a given type and manages creating the correct document, view, and frame window objects for that type.

What do you want to do?

  • Learn more about document/view

  • Learn the advantages of document/view

  • Learn more about:
    • Document templates

    • Documents

    • Views

    • Frame windows
  • Learn how MFC creates a document and its views and frame window(s)

  • Create a program with multiple document types, such as text documents and graphics documents

  • Create a document with multiple views

  • Create a splitter window, with separate panes containing instances of the same or different view objects

  • Learn about alternatives to document/view.


Help: Context-Sensitive Help Overview

Home | How Do I | Details | Sample | Tutorial

MFC makes it relatively easy to supply context-sensitive Windows help for your dialog boxes and commands. The MFC framework includes a help architecture that responds to the F1 and SHIFT+F1 key combinations and runs WinHelp.exe. With additional work, you can implement help for individual controls in a dialog box.

MFC supplies tools to simplify building your help files and several rich-text format (.rtf) files that document standard commands. You can customize these files to complete your help.

What do you want to do?

  • Help Topics (WinHelp): Context-Sensitive Help for Your Programs

  • Help Topics (HTML Help): Context-Sensitive Help for Your Programs

  • Create help for my application


Menus: Overview

Home | How Do I | Sample | Tutorial

MFC supplies two elements to help you work with menus:

  • Class CMenu for manipulating your program’s menus at run time. Use the documentation for CMenu and the sample to learn how to use CMenu effectively.

  • A mechanism for updating menus and toolbar buttons: enabling or disabling them on the fly to suit current program conditions.

Visual C++ also provides a menu editor for creating and editing your program's menu resources.

What do you want to do?

  • Learn more about class CMenu

  • Learn more about menu updating


OLE: User-Interface Overview

Home | How Do I | Details

Implementing OLE functionality in your program affects your user interface in several ways:

  • Visual editing (in-place activation) displays the user interface of another program in your program's windows and modifies your program's menus with items from the other program.

  • Drag and drop allows users to drag objects within and between windows and even between programs.

  • Trackers provide visual cues to the state of objects during visual editing and drag and drop.

What do you want to know more about?

  • OLE

  • Overview of OLE in MFC

  • Visual editing (see Activation)

  • Drag and drop

  • Trackers


Printing and Print Preview: Overview

Home | How Do I | Details | Sample | Tutorial

MFC supports printing and print preview for your program's documents via class CView. For basic printing and print preview, simply override your view class's OnDraw member function — which you must do anyway. That function can draw to the view on the screen, to a printer device context for an actual printer, or to a device context that simulates your printer on the screen.

You can also add code to manage multipage document printing and preview, to paginate your printed documents, and to add headers and footers to them.

What do you want to do?

  • Learn more about printing in MFC

  • Learn more about print preview in MFC


Property Sheets: Overview

Home | How Do I | Details | Sample

A property sheet, also known as a tab dialog box, is a dialog box that contains property pages. Each page contains controls, is based on a dialog template resource, and appears on a “tab,” an enclosure that looks like a file folder with a tab at the top. The tab names the page and indicates its purpose. Users click a tab in the property sheet to select a set of controls.

Use pages to group the controls in the property sheet into meaningful sets. The containing property sheet normally has several controls of its own. These apply to all pages.

For example, several dialog boxes in the development environment are property sheets, including the Options dialog box.

Property sheets are based on class CPropertySheet. Property pages are based on class CPropertyPage.

What do you want to do?

  • Learn about property sheets

  • Create a property sheet dialog box


Status Bars: Overview

Home | How Do I | Details | Tutorial

A status bar is a control bar with one or more panes. Each pane can contain text or bitmaps. You can use the panes to display various kinds of status information, such as command descriptions, time of day, page numbers, or the status of a key or option.

Create a status bar in your program by selecting the Initial Status Bar option in AppWizard.

What do you want to do?

  • Learn more about status bars.

  • Modify the contents of a status bar pane


Resource Editors: Overview

Home | How Do I | Details

Visual C++ and its development environment supply the resource editors listed below for editing the contents of your program’s resource (.RC) file:

  • Accelerator Editor

  • Binary Data Editor

  • Dialog Editor

  • Graphics Editor

  • Menu Editor

  • String Editor

  • Symbol Editor

  • Toolbar Editor

  • Editor

In Visual C++ version 5.x, resource-editor functionality specific to Visual C++ (not used in other tools in the development environment) affects the following editors:

  • Dialog Editor Topics for Visual C++ Importing Visual Basic Forms; dialog editor tips

  • Graphics Editor Topics for Visual C++ Creating or editing icons and cursors

  • Menu Editor Topics for Visual C++ Creating pop-up menus; associating a menu item with an accelerator key or with a status-bar prompt

  • Symbol Editor Topics for Visual C++ Creating and editing symbols: symbolic names associated with a numeric value

  • Version Editor Topics for Visual C++ Editing version information

Visual C++ also supplies sample resources, such as icons, cursors, and toolbar buttons.

What do you want to do?

Click the name of an editor above for details about tasks specific to Visual C++.


Tool Tips: Overview

Home | How Do I | Details

Tool tips are the tiny popup windows that present short descriptions of a toolbar button’s purpose when you position the mouse over a button for a period of time. MFC supports tool tips for your toolbars and for controls contained by windows that derive from class CFrameWnd. You can also use tool tips in windows not derived from CFrameWnd.

What do you want to do?

  • Learn about tool tips in windows derived from CFrameWnd

  • Learn about tool tips in windows not derived from CFrameWnd


Toolbars: Overview

Home | How Do I | Details | Sample | Tutorial

A toolbar is a control bar that contains the bitmap images of controls. These images can behave like pushbuttons, check boxes, or radio buttons. MFC supplies class CToolbar to manage toolbars.

If you enable it, users of MFC toolbars can dock them to the edge of a window or "float" them anywhere within the application window. MFC doesn’t support customizable toolbars like those in the development environment.

MFC also supports tool tips: small pop-up windows that describe a toolbar button's purpose when you position the mouse over the button. By default, when the user presses a toolbar button, a status string appears in the status bar (if there is one). You can activate "fly by" status bar updating to display the status string when the mouse is positioned over the button without pressing it.

Note As of MFC version 4.0, toolbars and tool tips are implemented using Windows 95 functionality instead of the previous implementation specific to MFC. For more information, see the article Toolbars.

For backward compatibility, MFC retains the older toolbar implementation in class COldToolBar. The documentation for earlier versions of MFC describe COldToolBar under CToolBar.

Create a first toolbar in your program by selecting the Initial Toolbar option in AppWizard. You can also create additional toolbars.

What do you want to do?

  • Learn more about toolbars

  • Create first a toolbar

  • Create additional toolbars after running AppWizard

  • Add a button to a toolbar

  • Implement tool tips on a toolbar

  • Implement fly-by status information for a toolbar


Window Objects: Overview

Home | How Do I | Details | Tutorial

MFC supplies class CWnd to encapsulate the HWND handle of a window. The CWnd object is a C++ window object, distinct from the HWND that represents a Windows window but containing it. Use CWnd to derive your own child window classes, or use one of the many MFC classes derived from CWnd. Class CWnd is the base class for all windows, including frame windows, dialog boxes, child windows, controls, and control bars such as toolbars.

MFC uses classes CFrameWnd, CMDIFrameWnd, and CMDIChildWnd to represent single document interface (SDI) and multiple document interface (MDI) frame windows.

MFC manages windows, but you can derive your own classes and use CWnd member functions to customize these windows. You can create child windows by constructing a CWnd object and calling its Create member function, then manage the child windows with other CWnd member functions. You can embed objects derived from CView, such as form views or tree views, in a frame window. And you can support multiple views of your documents via splitter panes, supplied by class CSplitterWnd.

Each object derived from class CWnd contains a message map, through which you can map Windows messages or command IDs to your own handler functions for them.

What do you want to know more about?

  • C++ window objects vs. HWNDs

  • Frame windows

  • Child windows

  • Views

  • Splitter windows

  • Message maps

  • Handler functions


Adding User-Interface Features: How Do I

Home | Overview | Details | FAQ

See the following lists of how-to topics for adding user-interface features to your program:

Comprehensive List of MFC Tasks

  • MFC Tasks

Detailed Lists of Tasks, Including MFC

  • ActiveX Control Tasks

  • Clipboard Tasks

  • Control Tasks

  • Device Context Tasks

  • Dialog-Bar Tasks

  • Dialog-Box Tasks

  • Document/View Tasks

  • Help Tasks: Context-Sensitive Help for Your Programs

  • Menu Tasks

  • OLE Tasks

  • Printing and Print Preview Tasks

  • Property Sheet Tasks

  • Resource Editor Tasks

  • Status-Bar Tasks

  • Toolbar Tasks

  • Tool Tip Tasks

  • Window Tasks

See Also Resource Editor Tasks (Specific to Visual C++), Resources


ActiveX Control Tasks

Home | Overview | Details | Tutorial | Sample

ActiveX controls were formerly known as OLE Controls. For information on beginning your ActiveX control project, see Overview: Creating an MFC ActiveX Control Program.

What do you want to do?

Categories of tasks covered in this topic include:

  • Installing and Getting Started with ActiveX Controls

  • Events, Methods, and Properties of ActiveX Controls

  • Optimizing ActiveX Controls

  • Containers for ActiveX Controls

  • Visual Aspects of ActiveX Controls

  • Property Pages for ActiveX Controls

  • VBX and CDK Migration

  • Database Access in ActiveX Controls

  • Miscellaneous ActiveX Control Tasks

Installing and Getting Started with ActiveX Controls

  • Install ActiveX control classes and tools

  • Creating an MFC ActiveX Control Program

  • Prepare and register an ActiveX control

  • License an ActiveX control

  • Localize (internationalize) an ActiveX control

  • Distribute my ActiveX control

  • Adding an ActiveX Control to a Dialog Box or other ActiveX control container

Events, Methods, and Properties of ActiveX Controls

  • Add stock events to an ActiveX control

  • Add custom events to an ActiveX control

  • Handle events from an ActiveX control

  • Create an ActiveX control event handler function

  • Add stock methods to an ActiveX control

  • Add custom methods to an ActiveX control

  • Add stock properties to an ActiveX control

  • Add custom properties to an ActiveX control

  • Implement a parameterized property in an ActiveX control

  • Give an ActiveX control read-only or write-only properties

  • Return error codes from an ActiveX control method

  • Return error codes from an ActiveX control property

  • Access ambient properties of a control container from an ActiveX control

Optimizing ActiveX Controls

  • Optimize an ActiveX control

Containers for ActiveX Controls

  • Create an ActiveX control container application

  • Manually enable ActiveX control containment in my application

  • Insert an ActiveX control into an ActiveX control container application

  • View and modify ActiveX control properties in a container application

  • Program my ActiveX control from its container application

  • Use my ActiveX control in a non-dialog container

  • Access ambient properties of a control container from an ActiveX control

  • Test an ActiveX control with Test Container

  • Test events, methods, and properties of an ActiveX control

Visual Aspects of ActiveX Controls

  • Paint an ActiveX control

  • Use fonts in an ActiveX control

  • Use pictures in an ActiveX control

Property Pages for ActiveX Controls

  • Implement a property page for an ActiveX control

  • Add extra property pages for an ActiveX control

  • Use a stock property page for an ActiveX control

VBX and CDK Migration

  • Migrate my VBX control to an ActiveX control

  • Convert a CDK project to a Visual C++ project

  • Add an ActiveX control project to an existing CDK project

Database Access in ActiveX Controls

  • Use database classes in an ActiveX control

  • Use data binding in an ActiveX control

Miscellaneous ActiveX Control Tasks

  • Handle errors in my ActiveX control

  • Handle special keys in my ActiveX control

  • Serialize an ActiveX control

  • Create an ActiveX control by subclassing a Windows control


ActiveX Control Sample List

Home | Overview | Tutorial

For sample ActiveX control projects, see the following list of samples under the topic CONTROLS:

  • BUTTON

  • CIRC1

  • CIRC2

  • CIRC3

  • DB

  • LICENSED

  • LOCALIZE

  • PAL

  • PUSH

  • REGSVR

  • SPINDIAL

  • TIME

  • XLIST

CIRC1, CIRC2, and CIRC3 represent steps in the ActiveX control tutorial.

Also see SMILEY, an ActiveX control container sample. The TESTHELP sample shows how to implement Help for an ActiveX control with property sheets.


Clipboard Tasks

Home | Overview | Details

The following tasks cover implementing:

  • The standard Windows Edit menu commands

  • Uniform data transfer (OLE), for implementing features like drag and drop

What do you want to do?

  • Use the Windows clipboard

  • Use the clipboard with OLE

  • Copy data to the clipboard (OLE)

  • Paste data from the clipboard (OLE)

  • Add clipboard formats (OLE)


Control Tasks

Home | Overview | Details | Sample

Windows common controls simplify creating complex dialog boxes. The list of available controls expanded with Windows 95.

What do you want to do?

  • Use Windows common controls

  • Add controls to a dialog box with the dialog editor

  • Add controls with code

  • Derive a control from a standard Windows control

  • Access dialog-box controls with type safety

  • Use a common control as a child window

  • Receive notification messages from common controls

For information about Windows common controls in the Win32 Software Development Kit (SDK), see Common Controls in the Win32 Programmer's Reference.

See Also ActiveX Control Tasks, Dialog Editor, Dialog Editor Topics (Specific to Visual C++)


Common Control Sample List

Home | Overview | Details

See the following sample programs that illustrate common controls:

  • CMNCTRL1

  • CMNCTRL2

  • CTRLTEST

  • FIRE

Back to Control Tasks


Control-Bar Tasks: Toolbars, Status Bars, Dialog Bars

Home | Overview | Details | Sample

“Control bar” is the general name for toolbars, status bars, and dialog bars. Classes CToolBar, CStatusBar, and CDialogBar derive from class CControlBar, which implements their common functionality.

What do you want to do?

  • Work with toolbars

  • Work with status bars

  • Work with dialog bars


Dialog-Bar Tasks

Home | Overview | Details | Sample

Dialog bars are control bars with the characteristics of a toolbar combined with the characteristics of a dialog box.

What do you want to do?

  • Create a dialog bar


Dialog-Box Tasks

Home | Overview | Details | Sample | Tutorial

Create dialog boxes when you need to obtain information from your user, such as program settings and options. Two fundamental types of dialog boxes are available: modal and modeless dialog boxes. Either of these can contain all types of controls, and either can include property pages to group controls logically.

What do you want to do?

Categories of tasks covered in this topic include:

  • Basic Dialog-Box Tasks

  • Displaying, Initializing, and Closing Dialog Boxes

  • Working with Dialog-Box Data

  • Implementing Property-Sheet Dialog Boxes

  • Working with Dialog Classes and Common Dialogs

  • Advanced Dialog-Box Tasks

Basic Dialog-Box Tasks

  • Create a modal dialog box

  • Create a modeless dialog box

Displaying, Initializing, and Closing Dialog Boxes

  • Initialize a dialog box

  • Retrieve data from a dialog box

  • Close a dialog box

  • Destroy a dialog box

Working with Dialog-Box Data

  • Use dialog data exchange (DDX)

  • Validate dialog-box data with dialog data validation (DDV)

Implementing Property-Sheet Dialog Boxes

  • Implement a property-sheet dialog box

  • Exchange data between a property sheet and your application

  • Create a modeless property sheet

  • Handle the Apply button on a property sheet

Working with Dialog Classes, and Common Dialogs

  • Access dialog controls with type safety

  • Override dialog class member functions

  • Use the common dialog classes

Advanced Dialog-Box Tasks

  • Set the background color of a dialog box

  • Use a dialog template in memory

  • Create an application whose user interface is a dialog box: see the CMNCTRL1 or CMNCTRL2 sample programs. AppWizard provides this option as well.

See Also Dialog Editor Topics (Specific to Visual C++), Dialog Editor


Dialog Sample List

Home | Overview | How Do I | Details | Tutorial

See the following sample programs that illustrate dialog boxes and property sheets:

Tutorial Sample

  • SCRIBBLE

Modeless Dialog Box

  • MODELESS

Property Sheet Dialog Box (Tab Dialog Box)

  • PROPDLG

  • CMNCTRL1

  • CMNCTRL2

Application Based on a Dialog Box

  • CMNCTRL1

  • CMNCTRL2

Dialog-Box Controls

  • CMNCTRL1

  • CMNCTRL2

  • CTRLTEST

Dialog-Like Form Views

  • VIEWEX

In-Memory Dialog Template

  • DLGTEMPL

Back to Dialog-Box Tasks


Document/View Tasks

Home | Overview | Details | Sample | Tutorial

By default, AppWizard creates an application skeleton with a document class and a view class. MFC separates data management into these two classes. The document stores the data and manages printing the data and coordinates updating multiple views of the data. The view displays the data and manages user interaction with it, including selection and editing.

For the rationale behind separating document from view, see Document/View Architecture: Overview. For alternatives to document/view, see Alternatives to the Document/View Architecture.

What do you want to do?

MFC Document Tasks

  • Store data in a document class

  • Initialize documents and views

  • Initialize your own additions to document & view classes

  • Clean up documents and views

  • Create multiple document types

MFC View Tasks

  • Display data in a view

  • Draw in a view

  • Interpret user input through a view

  • Scroll a view

  • Scale a view

  • Create multiple views on a document

  • Use a form view, a view with dialog-box controls

  • Use a record view to display database records

Advanced Document/View Tasks

  • Bypass the archive mechanism in MFC serialization

  • Bypass the document/view mechanism

See Also Window Tasks


Document/View Sample List

Home | Overview | Tutorial

See the following sample programs that illustrate using MFC's document/view architecture in interesting ways:

Tutorial Sample

  • SCRIBBLE

No Document/View

  • HELLOAPP

Document/View Variations

  • HELLO

  • MDI

  • VIEWEX

Document as Interface to Database

  • CHKBOOK

Tree and List Views

  • DAOVIEW

Form Views

  • ENROLL

Dialog-Box Interface Replaces Document/View

  • CMNCTRL1

  • CMNCTRL2

Using COleDocument and Its Derived Classes

  • CONTAINER

  • HIERSVR

  • OCLIENT

Back to Document/View Tasks


Help Tasks: Context-Sensitive Help for Your Programs

Home | Overview | Details | Sample | Tutorial

MFC provides an architecture that simplifies implementing your own help files for your application.

What do you want to do?

The following links display topics that discuss context-sensitive help and WinHelp.

  • Create online help for your application

  • Implement F1 help support

  • Implement SHIFT+F1 help support

  • Compile your application’s help file

  • Build your help files

  • Work with your application’s help project (.hpj) file

  • Create help for property sheets and property pages

  • Author your application’s help topics

The following link displays a topic that discusses context-sensitive help and HTML Help.

  • Help Topics (HTML Help): Context-Sensitive Help for Your Programs


Menu Tasks

Home | Overview | Sample | Tutorial

MFC provides class CMenu for manipulating your program’s menus. MFC message maps also simplify managing the enabled/disabled state of menu items and toolbar buttons.

What do you want to do?

  • Update menus and toolbar buttons to reflect program conditions

  • Dynamically modify menus using class CMenu

See Also Menu Editor Topics (Specific to Visual C++), Menu Editor


Menu Sample List

Home | Overview | Tutorial

See the following sample programs that illustrate creating, editing, and updating menus:

Tutorial Sample: Enable and Disable Menu Items

  • SCRIBBLE

Dynamically Change Menus

  • DYNAMENU

Back to Menu Tasks


OLE Tasks Affecting the User Interface

Home | Overview

See OLE Tasks


Printing and Print-Preview Tasks

Home | Overview | Details | Sample | Tutorial

MFC supplies an architecture for printing and print preview. By default, print preview just works, although you can modify it.

You must do some work for printing, primarily implementing your view’s OnDraw member function. The printing architecture makes use of OnDraw; you draw to the printer just as you would to a view. If necessary, you can modify how this works or override it all together. For example, you might use a conditional to determine what is drawn to the screen and what is drawn to the printer.

What do you want to do?

  • Print your document

  • Print multipage documents

  • Paginate your printed document

  • Add headers and footers to your printed document

  • Allocate GDI resources while printing

  • Modify print preview behavior and appearance


Property Sheet Tasks

Home | Overview | Details | Sample

Use a property sheet dialog box when you have large numbers of controls to organize. You can group the controls meaningfully and put each group on a separate property page within the property sheet.

What do you want to do?

  • Use property sheets in my application

  • Add property pages to a property sheet

  • Display a property sheet

  • Add controls to a property sheet

  • Exchange data between a property sheet and my program

  • Create a modeless property sheet

  • Handle the Apply button on my property sheet


Resource Editor Tasks

Home | Overview | Details

The integrated development environment provides resource editors for editing the resources in your program’s resource (.RC) file. The following tasks cover using those editors. Visual C++ also supplies sample resources, such as icons, cursors, and toolbar buttons, that you can use in your programs.

What do you want to do?

Topics on the Resource Editors

  • Create or edit accelerator key assignments

  • Create or edit binary data resources

  • Create or edit dialog boxes

  • Create or edit images: bitmaps, icons, cursors

  • Create or edit menus

  • Create or edit string resources

  • Create or edit symbols

  • Create or edit toolbars

  • Create or edit version information resources

General Resource Editing Topics

  • Work with resource files

  • Import resource script files created by other applications

  • Add MFC support to resource script files

  • Use advanced resource file techniques

  • Change the name of the symbol header file

  • Use shared (read-only) or calculated symbols

  • Include resources from other files

  • Change resources while copying them

  • Change the language of a resource

  • Change the property condition of a resource

  • Import and export resources

  • Property pages for ActiveX controls and accelerator keys

Dialog Editor Topics

  • Use the dialog editor in Visual C++

  • Import a Visual Basic form

  • Use ActiveX controls in a dialog box

  • See tips for using the dialog editor effectively in Visual C++

Graphics Editor Topics

  • Use the graphics editor in Visual C++

  • Create or edit icons and cursors

Menu Editor Topics

  • Use the menu editor in Visual C++

  • Create pop-up menus

  • View the menu resource as a pop-up menu

  • Associate a menu item with an accelerator key

  • Associate a menu item with a status bar prompt

Symbol Editor Topics

  • Use the symbol editor

  • Learn about working with symbols

  • Learn about symbol name restrictions

  • Learn about symbol value restrictions

  • Change a symbol or symbol name

  • Change a symbol’s numerical value

  • Manage symbols with the Resource Symbols browser

  • Change the name of the symbol header file

  • Use shared (read-only) or calculated symbols

Version Editor Topic

  • Use the version editor in Visual C++


Status-Bar Tasks

Home | Overview | Details | Tutorial

Status bars are control bars that let you display information to your user in a set of panes or “indicators.”

Create a status bar in your program by selecting the Initial Status Bar option in AppWizard.

What do you want to do?

  • Work with status bars

  • Display command information in the status bar

  • Create a new status-bar pane

  • Make a status-bar pane display text

  • Update the text of a status-bar pane


Tool Tip Tasks

Home | Overview | Details

Use tool tips to help users identify the purpose of a toolbar button or other control.

What do you want to do?

Window Is Derived from CFrameWnd: Including Toolbars

  • Activate tool tips for controls in a window derived from CFrameWnd

  • Enable fly by status-bar updates

Window Not Derived from CFrameWnd: Form Views and Dialog Boxes

  • Enable tool tips for controls in a window not derived from CFrameWnd

  • Learn when I need to handle the TTN_NEEDTEXT message

  • Enable tool tips for child controls in a form view or dialog box

  • Handle the TTN_NEEDTEXT message

  • Learn about the TOOLTIPTEXT structure

  • Learn how to specify the string to be displayed in a tool tip


Toolbar Tasks

Home | Overview | Details | Sample | Tutorial

Toolbars are control bars that contain command buttons.

What do you want to do?

Basic Toolbar Tasks

  • Add a first toolbar to your application

  • Add extra toolbars to your application

  • Update menus and toolbar buttons to reflect program conditions

  • Use the older implementation of CToolbar

Toolbar Docking and Floating Tasks

  • Enable toolbar docking

  • Dock a toolbar

  • Float a toolbar

  • Dynamically resize a toolbar

  • Specify whether a floating toolbar is fixed or dynamically resizable

  • Set wrap positions for a fixed-style toolbar

Tooltip and Fly-By Status-Bar Update Tasks

  • Activate tooltips for a toolbar

  • Implement fly by status bar updates

Advanced Toolbar Tasks

  • Access the toolbar control underlying a toolbar

See Also Toolbar Editor


Toolbar Sample List

Home | Overview | Details | Tutorial

See the following sample programs that illustrate using MFC's toolbars:

Tutorial Sample

  • SCRIBBLE

Other Toolbar Samples

  • CTRLBARS

  • DOCKTOOL

Back to Toolbar Tasks


Window Tasks

Home | Overview | Details | Tutorial

MFC supplies a large number of classes to represent various kinds of window objects, including frame windows, child windows, views, dialog boxes, and controls.

What do you want to do?

Create and Destroy Windows

  • Create child windows

  • Destroy window objects

  • Create document frame windows

  • Destroy frame windows

Create Splitter Windows

  • Create splitter windows

Manage Child Windows and the Current View

  • Manage MDI child windows

  • Manage the current view

  • Manage menus, control bars, and accelerators

Work with Device Contexts and Window Styles

  • Use device contexts

  • Use pens and other graphic objects in a device context

  • Change the styles of a window created by MFC

See Also Document/View Tasks, Dialog-Box Tasks, Toolbar Tasks, Status-Bar Tasks, Dialog-Bar Tasks


Adding User-Interface Features: Frequently Asked Questions

Home | Overview | How Do I | Details

Questions about adding user-interface features:

  • Why do we distinguish between program functionality and user-interface features?

  • What are Microsoft’s guidelines for user-interface design in Windows?

  • Does Visual C++ supply any “clip art” resources such as icons, cursors, toolbar buttons?


Adding User-Interface Features: Details

Home | Overview | How Do I | FAQ

Sometimes you need broader and deeper coverage of a subject, especially when you are learning a new skill. For such information about the topics covered by the Adding User-Interface Features book, see the following families of articles:

  • ActiveX Control Topics

  • Clipboard Topics

  • Control Topics

  • Control Bar Topics

  • Dialog Bar Topics

  • Dialog Box Topics

  • Document/View Architecture Topics

  • Form Topics

  • Help Topics (WinHelp): Context-Sensitive Help for Your Programs

  • Help Topics (HTML Help): Context-Sensitive Help for Your Programs

  • Menu Topics

  • Printing and Print Preview Topics

  • Property Sheet Topics

  • Resource Editor Topics (Specific to Visual C++)

  • Status Bar Topics

  • Toolbar Topics

  • Window Topics

For additional topics related to these, see Where to Find More on Adding User-Interface Features.


Where to Find More Information on Adding User-Interface Features

Home | Overview | How Do I | FAQ

Besides the topics listed in Details: Adding User-Interface Features, OLE contributes some user-interface elements:

  • Visual Editing (see In-Place Activation in the destination topic)

  • Drag and drop

  • Trackers


ActiveX Control Topics

Home | Overview | How Do I | FAQ | Sample | Tutorial

An ActiveX control (formerly known as an OLE control) is a reusable software component that supports a wide variety of OLE functionality and can be customized to fit many software needs. ActiveX controls are designed for use both in ordinary ActiveX control containers and on the Internet, in World Wide Web pages. You can create ActiveX controls either with MFC, described in this article family, or with Active Template Library (ATL).

For some recent information on optimizing your ActiveX controls, see ActiveX Controls: Optimization.

What do you want to know more about?

Basic ActiveX Control Information

  • What ActiveX controls are

  • ActiveX control containers

  • ActiveX

  • The Control Test Container, used for testing ActiveX controls

  • Install ActiveX control classes and tools

Programming ActiveX Controls

  • Painting an ActiveX control

  • ActiveX control events

  • ActiveX control methods

  • ActiveX control properties

  • ActiveX control property pages

  • Fonts in ActiveX controls

  • Pictures in ActiveX controls

  • Distributing ActiveX controls

  • Licensing ActiveX controls

  • Localizing ActiveX controls

  • Serializing ActiveX controls

  • Subclassing a Windows control

  • Data binding in an ActiveX control

  • Optimizing an ActiveX control

Control Migration

  • Migrating a Visual Basic control (VBX)

  • Adding an ActiveX control to an existing Control Development Kit (CDK) project

  • Converting a CDK project to a Visual C++ project

Advanced ActiveX Control Topics

  • Using database classes in ActiveX controls

  • Parameterized properties

  • Error handling in an ActiveX control

  • Handling special keys in an ActiveX control

  • Accessing dialog controls that are invisible at run time


ActiveX Controls

Home | Overview | How Do I | FAQ | Tutorial | Sample

An ActiveX control is implemented as an in-process server (typically a small object) that can be used in any OLE container. Note that the full functionality of an ActiveX control is available only when used within an OLE container designed to be aware of ActiveX controls. The following products and all their subsequent releases fully support ActiveX controls: Microsoft FoxPro 3.0, Microsoft Access 2.0, Microsoft Visual Basic 4.0, and OLE containers built with MFC in Visual C++ version 4.0. This container type, hereafter called a “control container,” can operate an ActiveX control by using the control’s properties and methods, and receives notifications from the ActiveX control in the form of events. The following figure demonstrates this interaction.

Interaction Between an ActiveX Control Container and a Windowed ActiveX Control

These articles describe creating ActiveX controls with MFC. For information on creating ActiveX controls with ActiveX Template Library (ATL), see the ATL reference.

Basic Components of an ActiveX Control

An ActiveX control uses several programmatic elements to interact efficiently with a control container and with the user. These are class COleControl, a set of event-firing functions, and a dispatch map.

Every ActiveX control object you develop inherits a powerful set of features from its MFC base class, COleControl. These features include in-place activation, and Automation logic. COleControl can provide the control object with the same functionality as an MFC window object, plus the ability to fire events. COleControl can also provide windowless controls, which rely on their container for help with some of the functionality a window provides (mouse capture, keyboard focus, scrolling), but offer much faster display.

Because the control class derives from COleControl, it inherits the capability to send, or “fire,” messages, called events, to the control container when certain conditions are met. These events are used to notify the control container when something important happens in the control. You can send additional information about an event to the control container by attaching parameters to the event. For more information about ActiveX control events, see the article ActiveX Controls: Events.

The final element is a dispatch map, which is used to expose a set of functions (called methods) and attributes (called properties) to the control user. Properties allow the control container or the control user to manipulate the control in various ways. The user can change the appearance of the control, change certain values of the control, or make requests of the control, such as accessing a specific piece of data that the control maintains. This interface is determined by the control developer and is defined using ClassWizard. For more information on ActiveX control methods and properties, see the articles ActiveX Controls: Methods and Properties.

Interaction Between Controls with Windows and ActiveX Control Containers

When a control is used within a control container, it uses two mechanisms to communicate: it exposes properties and methods, and it fires events. The following figure demonstrates how these two mechanisms are implemented.

Communication Between an ActiveX Control Container and an ActiveX Control

The above figure also illustrates how other OLE interfaces (besides automation and events) are handled by controls.

All of a control’s communication with the container is performed by COleControl. To handle some of the container’s requests, COleControl will call member functions that are implemented in the control class. All methods and some properties are handled in this way. Your control’s class can also initiate communication with the container by calling member functions of COleControl. Events are fired in this manner.

Active and Inactive States of an ActiveX Control

A control has two basic states: active and inactive. Traditionally, these states were distinguished by whether or not the control had a window. An active control had a window; an inactive control did not. With the introduction of windowless activation, this distinction is no longer universal, but still applies to many controls.

When a windowless control goes active, it invokes mouse capture, keyboard focus, scrolling, and other window services from its container. You can also provide mouse interaction to inactive controls, as well as create controls that wait until activated to create a window.

When a control with a window becomes active, it is able to interact fully with the control container, the user, and Windows. The figure below demonstrates the paths of communication between the ActiveX control, the control container, and the operating system.

Windows Message Processing in a Windowed ActiveX Control (When Active)

Serialization

The ability to serialize data, sometimes referred to as persistence, allows the control to write the value of its properties to persistent storage. Controls can then be re-created by reading the object’s state from the storage.

Note that a control is not responsible for obtaining access to the storage medium. Instead, the control’s container is responsible for providing the control with a storage medium to use at the appropriate times. For more information on serialization, see the article ActiveX Controls: Serializing. For information on optimizing serialization, see Optimizing persistence and initialization in ActiveX Controls: Optimization.

Installing ActiveX Control Classes and Tools

When you install Visual C++, the MFC ActiveX control classes and retail and debug ActiveX control run-time DLLs are automatically installed if ActiveX controls are selected in Setup (they are selected by default). For more information on Test Container, see the article Test Container.

By default, the ActiveX control classes and tools are installed in the following subdirectories under \Program Files\Microsoft Visual Studio:

  • \VC98\Bin

    Contains the Test Container files (TstCon32.exe, as well as its Help files) as well as RegSvr32.exe.

  • \Common\msdev98\bin\ide

    Contains the executable for the ActiveX ControlWizard (MFCTLWZ.AWX).

  • \Common\msdev98\Help

    Contains the PSS help file (PSS.HLP) and the help file that discusses adding your own .HLP files to the development environment.

  • \VC98\MFC\Include

    Contains the include files needed to develop ActiveX controls with MFC

  • \VC98\MFC\Src

    Contains the source code for specific ActiveX control classes in MFC

  • \VC98\MFC\Lib

    Contains the libraries required to develop ActiveX controls with MFC

There are also samples for MFC ActiveX controls. Information about these samples is available online; search for sample.

Further Reading About ActiveX Controls

The articles listed below explain the details of developing ActiveX controls using Visual C++ and the MFC ActiveX control classes. The articles are listed in functional categories.

Frequently Asked Questions About ActiveX Controls

Articles about the ActiveX control development process

  • MFC ActiveX ControlWizard

  • MFC ActiveX ControlWizard: Step-by-Step

  • Prepare Your MFC ActiveX Control Program for Use (Register it)

  • Add Code to the MFC ActiveX Control Starter Files

  • Test Container

Articles about optimizing ActiveX controls

  • ActiveX Controls: Optimization

Articles about the events, methods, and properties of ActiveX controls

  • ActiveX Controls: Events

  • ActiveX Controls: Adding Stock Events to an ActiveX Control

  • ActiveX Controls: Adding Custom Events to an ActiveX Control

  • ActiveX Controls: Methods

  • Methods: Adding Stock Methods to an ActiveX Control

  • ActiveX Controls: Adding Custom Methods to an ActiveX Control

  • ActiveX Controls: Returning Error Codes From a Method

  • ActiveX Controls: Properties

  • ActiveX Controls: Adding Stock Properties

  • ActiveX Controls: Adding Custom Properties

  • ActiveX Controls: Advanced Property Implementation

  • ActiveX Controls: Accessing Ambient Properties

Articles about user-interface aspects of ActiveX controls

  • ActiveX Controls: Painting an ActiveX Control

  • ActiveX Controls: Property Pages

  • ActiveX Controls: Adding Another Custom Property Page

  • ActiveX Controls: Adding Context-Sensitive Help

  • ActiveX Controls: Using Stock Property Pages

  • ActiveX Controls: Using Fonts in an ActiveX control

  • ActiveX Controls: Using Pictures in an ActiveX Control

  • ActiveX Controls: Optimization

Articles about advanced topics of ActiveX controls

  • ActiveX Controls: Advanced Topics

  • ActiveX Controls: Distributing ActiveX Controls

  • ActiveX Controls: Licensing an ActiveX Control

  • ActiveX Controls: Localizing an ActiveX Control

  • ActiveX Controls: Serializing

  • ActiveX Controls: Subclassing a Windows Control

  • ActiveX Controls: Optimization

Other articles regarding ActiveX controls

  • ActiveX Controls: Using Data Binding in an ActiveX Control

  • ActiveX Controls: Adding an ActiveX Control to an Existing CDK Project

  • ActiveX Controls: VBX Control Migration

  • ActiveX Controls: Converting a CDK Project to a Visual C++ Project

Articles about creating ActiveX controls with ActiveX Template Library (ATL)

  • Creating Objects and Implementing Interfaces in ATL

See Also Test Container


ActiveX Controls: Optimization

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article explains techniques you can use to optimize your ActiveX controls for better performance.

What do you want to know more about?

  • Optimizing Persistence and Initialization

  • Providing Windowless Activation

  • Turning Off the Activate When Visible Option

  • Providing Mouse Interaction While Inactive

  • Providing Flicker-Free Activation

  • Using an Unclipped Device Context

  • Optimizing Control Drawing

The topics Turning Off the Activate When Visible Option and Providing Mouse Interaction While Inactive discuss controls that don’t create a window until activated. The topic Providing Windowless Activation discusses controls that never create a window, even when they are activated.

Windows have two major drawbacks for OLE objects: they prevent objects from being transparent or nonrectangular when active, and they add a large overhead to the instantiation and display of controls. Typically, creating a window takes 60 percent of a control’s creation time. With a single shared window (usually the container’s) and some dispatching code, a control receives the same window services, generally without a loss of performance. Having a window is mostly unnecessary overhead for the object.

Some optimizations do not necessarily improve performance when your control is used in certain containers. For example, containers released prior to 1996 did not support windowless activation, so implementing this feature will not provide a benefit in older containers. However, nearly every container supports persistence, so optimizing your control’s persistence code will likely improve its performance in any container. If your control is specifically intended to be used with one particular type of container, you may want to research which of these optimizations is supported by that container. In general, however, you should try to implement as many of these techniques as are applicable to your particular control to ensure your control performs as well as it possibly can in a wide array of containers.

You can implement many of these optimizations through ControlWizard.

ControlWizard OLE Optimization Options

ControlWizard Option | Action | More Information
Activate when visible checkbox on ControlWizard Step 2 of 2 | Clear | Turning Off the Activate When Visible Option
Windowless activation checkbox on ControlWizard Advanced ActiveX Features | Select | Providing Windowless Activation
Unclipped device context | Select | Using an Unclipped Device Context
Flicker-free activation checkbox on ControlWizard Advanced ActiveX Features | Select | Providing Flicker-Free Activation
Mouse pointer notifications when inactive checkbox on ControlWizard Advanced ActiveX Features | Select | Providing Mouse Interaction While Inactive
Optimized drawing code checkbox on ControlWizard Advanced ActiveX Features | Select | Optimizing Control Drawing

For detailed information about the member functions that implement these optimizations, see COleControl. The member functions are listed by use, such as Windowless Operations and Inactive Pointer Handling Functions.


Optimizing Persistence and Initialization

Home | Overview | How Do I | FAQ | Tutorial | Sample

By default, persistence and initialization in a control are handled by the DoPropExchange member function. In a typical control, this function contains calls to several PX_ functions (PX_Color, PX_Font, and so on), one for each property.

This approach has the advantage that a single DoPropExchange implementation can be used for initialization, for persistence in binary format, and for persistence in the so-called “property-bag” format used by some containers. This one function provides all information about the properties and their default values in one convenient place.

However, this generality comes at the expense of efficiency. The PX_ functions get their flexibility through multilayered implementations that are inherently less efficient than more direct, but less flexible, approaches. Furthermore, if a control passes a default value to a PX_ function, that default value must be provided every time, even in situations when the default value may not necessarily be used. If generating the default value is a nontrivial task (for example, when the value is obtained from an ambient property), then extra, unnecessary work is done in cases where the default value is not used.

You can improve your control’s binary persistence performance by overriding your control's Serialize function. The default implementation of this member function makes a call to your DoPropExchange function. By overriding it, you can provide a more direct implementation for binary persistence. For example, consider this DoPropExchange function:

void CMyCtrl::DoPropExchange(CPropExchange* pPX)
{
   ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
   COleControl::DoPropExchange(pPX);

   PX_Bool(pPX, _T("BoolProp"), m_boolProp, TRUE);
   PX_Short(pPX, _T("ShortProp"), m_shortProp, 0);
   PX_Color(pPX, _T("ColorProp"), m_colorProp, RGB(0xFF,0x00,0x00));
   PX_String(pPX, _T("StringProp"), m_stringProp, _T(""));
}

To improve the performance of this control’s binary persistence, you can override the Serialize function as follows:

void CMyCtrl::Serialize(CArchive& ar)
{
    DWORD dwVersion =
        SerializeVersion(ar, MAKELONG(_wVerMinor, _wVerMajor));
    SerializeExtent(ar);
    SerializeStockProps(ar);

    if (ar.IsLoading())
    {
        ar >> m_boolProp;
        ar >> m_shortProp;
        ar >> m_colorProp;
        ar >> m_stringProp;
    }
    else
    {
        ar << m_boolProp;
        ar << m_shortProp;
        ar << m_colorProp;
        ar << m_stringProp;
    }
}

The dwVersion local variable can be used to detect the version of the control’s persistent state being loaded or saved. You can use this variable instead of calling CPropExchange::GetVersion.

To save a little space in the persistent format for a BOOL property (and to keep it compatible with the format produced by PX_Bool), you can store the property as a BYTE, as follows:

    if (ar.IsLoading())
    {
        BYTE bTmp;
        ar >> bTmp;
        m_boolProp = (BOOL)bTmp;
        .
        .
        .
    }
    else
    {
        ar << (BYTE)m_boolProp;
        .
        .
        .
    }

Note that in the load case, a temporary variable is used and then its value is assigned, rather than casting m_boolProp to a BYTE reference. The casting technique would result in only one byte of m_boolProp being modified, leaving the remaining bytes uninitialized.

For the same control, you can optimize the control’s initialization by overriding COleControl::OnResetState as follows:

void CMyCtrl::OnResetState()
{
    ResetVersion(MAKELONG(_wVerMinor, _wVerMajor));
    ResetStockProps();

    m_boolProp = TRUE;
    m_shortProp = 0;
    m_colorProp = RGB(0xFF,0x00,0x00);
    m_stringProp.Empty();
}

Although Serialize and OnResetState have been overridden, the DoPropExchange function should be kept intact because it is still used for persistence in the property-bag format. It is important to maintain all three of these functions to ensure that the control manages its properties consistently, regardless of which persistence mechanism the container uses.


Providing Windowless Activation

Home | Overview | How Do I | FAQ | Tutorial | Sample

Window creation code (that is, everything that happens when you call CreateWindow) is costly to execute. A control that maintains an on-screen window has to manage messages for the window. Windowless controls are therefore faster than controls with windows.

A further advantage of windowless controls is that, unlike windowed controls, windowless controls support transparent painting and nonrectangular screen regions. A common example of a transparent control is a text control with a transparent background. The controls paints the text but not the background, so whatever is under the text shows through. Newer forms often make use of nonrectangular controls, such as arrows and round buttons.

Often, a control does not need a window of its own and, instead, can use the window services of its container, provided that the container has been written to support windowless objects. Windowless controls are backward compatible with older containers. In older containers not written to support windowless controls, the windowless controls simply create a window when active.

Since windowless controls do not have their own windows, the container (which does have a window) is responsible for providing services that would otherwise have been provided by the control’s own window. For example, if your control needs to query the keyboard focus, capture the mouse, or obtain a device context, these operations are managed by the container. The container routes user input messages sent to its window to the appropriate windowless control, using the IOleInPlaceObjectWindowless interface. (See the ActiveX SDK for a description of this interface.) COleControl member functions invoke these services from the container.

To make your control use windowless activation, include the windowlessActivate flag in the set of flags returned by COleControl::GetControlFlags. For example:

DWORD CMyCtrl::GetControlFlags()
{
    return COleControl::GetControlFlags() | windowlessActivate;
}

The code to include this flag is automatically generated if you select the Windowless Activation option on the Advanced ActiveX Features page of the ControlWizard dialog box.

When windowless activation is enabled, the container will delegate input messages to the control’s IOleInPlaceObjectWindowless interface. COleControl’s implementation of this interface dispatches the messages through your control’s message map, after adjusting the mouse coordinates appropriately. You can process the messages like ordinary window messages, by adding the corresponding entries to the message map. In your handlers for these messages, avoid using the m_hWnd member variable (or any member function that uses it) without first checking that its value is not NULL.

COleControl provides member functions that invoke mouse capture, keyboard focus, scrolling, and other window services from the container as appropriate, including:

  • GetFocus, SetFocus

  • GetCapture, SetCapture, ReleaseCapture

  • GetDC, ReleaseDC

  • InvalidateRgn

  • ScrollWindow

  • GetClientRect

In windowless controls, you should always use the COleControl member functions instead of the corresponding CWnd member functions or their related Win32 API functions.

You may want a windowless control to be the target of an OLE drag-and-drop operation. Normally, this would require that the control’s window be registered as a drop target. Since the control has no window of its own, the container uses its own window as a drop target. The control simply provides an implementation of the IDropTarget interface to which the container can delegate calls at the appropriate time. To expose this interface to the container, override COleControl::GetWindowlessDropTarget. For example:

IDropTarget* CMyCtrl::GetWindowlessDropTarget()
{
    m_xDropTarget.AddRef();
    return &m_xDropTarget;
}


Turning off the Activate When Visible Option

Home | Overview | How Do I | FAQ | Tutorial | Sample

A control has two basic states: active and inactive. Traditionally, these states were distinguished by whether or not the control had a window. An active control had a window; an inactive control did not. With the introduction of windowless activation, this distinction is no longer universal, but still applies to many controls.

Compared with the rest of the initialization typically performed by an ActiveX control, the creation of a window is an extremely expensive operation. Ideally, a control would defer creating its window until absolutely necessary.

Many controls do not need to be active the entire time they are visible in a container. Often, a control can remain in the inactive state until the user performs an operation that requires it to become active (for example, clicking with the mouse or pressing the TAB key). To cause a control to remain inactive until the container needs to activate it, remove the OLEMISC_ACTIVATEWHENVISIBLE flag from the control’s miscellaneous flags:

static const DWORD BASED_CODE _dwMyOleMisc =
   OLEMISC_SETCLIENTSITEFIRST |
   OLEMISC_INSIDEOUT |
   OLEMISC_CANTLINKINSIDE |
   OLEMISC_RECOMPOSEONRESIZE;

The OLEMISC_ACTIVATEWHENVISIBLE flag is automatically omitted if you turn off the Activate When Visible option when creating your control with ControlWizard.


Providing Mouse Interaction While Inactive

Home | Overview | How Do I | FAQ | Tutorial | Sample

If your control is not immediately activated, you may still want it to process WM_SETCURSOR and WM_MOUSEMOVE messages, even though the control has no window of its own. This can be accomplished by enabling COleControl’s implementation of the IPointerInactive interface, which is disabled by default. (See the ActiveX SDK for a description of this interface.) To enable it, include the pointerInactive flag in the set of flags returned by COleControl::GetControlFlags:

DWORD CMyCtrl::GetControlFlags()
{
    return COleControl::GetControlFlags() | pointerInactive;
}

The code to include this flag is automatically generated if you select the Mouse Pointer Notifications When Inactive option on the Advanced ActiveX Features page when creating your control with ControlWizard.

When the IPointerInactive interface is enabled, the container delegates WM_SETCURSOR and WM_MOUSEMOVE messages to it. COleControl’s implementation of IPointerInactive dispatches the messages through your control’s message map after adjusting the mouse coordinates appropriately. You can process the messages just like ordinary window messages by adding the corresponding entries to the message map. In your handlers for these messages, avoid using the m_hWnd member variable (or any member function that uses it) without first checking that its value is not NULL.

You may also want an inactive control to be the target of an OLE drag-and-drop operation. This requires activating the control at the moment the user drags an object over it, so that the control’s window can be registered as a drop target. To cause activation to occur during a drag, override COleControl::GetActivationPolicy, and return the POINTERINACTIVE_ACTIVATEONDRAG flag:

DWORD CMyCtrl::GetActivationPolicy()
{
    return POINTERINACTIVE_ACTIVATEONDRAG;
}

Enabling the IPointerInactive interface typically means that you want the control to be capable of processing mouse messages at all times. To get this behavior in a container that doesn’t support the IPointerInactive interface, you need to have your control always activated when visible, which means the control should include the OLEMISC_ACTIVATEWHENVISIBLE flag among its miscellaneous flags. However, to prevent this flag from taking effect in a container that does support IPointerInactive, you can also specify the OLEMISC_IGNOREACTIVATEWHENVISIBLE flag:

static const DWORD BASED_CODE _dwMyOleMisc =
    OLEMISC_ACTIVATEWHENVISIBLE |
    OLEMISC_IGNOREACTIVATEWHENVISIBLE |
    OLEMISC_SETCLIENTSITEFIRST |
    OLEMISC_INSIDEOUT |
    OLEMISC_CANTLINKINSIDE |
    OLEMISC_RECOMPOSEONRESIZE;


Providing Flicker-Free Activation

Home | Overview | How Do I | FAQ | Tutorial | Sample

If your control draws itself identically in the inactive and active states (and does not use windowless activation), you can eliminate the drawing operations and the accompanying visual flicker that normally occur when making the transition between the inactive and active states. To do this, include the noFlickerActivate flag in the set of flags returned by COleControl::GetControlFlags. For example:

DWORD CMyCtrl::GetControlFlags()
{
    return COleControl::GetControlFlags() | noFlickerActivate;
}

The code to include this flag is automatically generated if you select the Flicker-Free Activation option on the Advanced ActiveX Features page when creating your control in ControlWizard.

If you are using windowless activation, this optimization has no effect.


Using an Unclipped Device Context

Home | Overview | How Do I | FAQ | Tutorial | Sample

If you are absolutely certain that your control doesn’t paint outside its client rectangle, you can realize a small but detectable speed gain by disabling the call to IntersectClipRect that is made by COleControl. To do this, remove the clipPaintDC flag from the set of flags returned by COleControl::GetControlFlags. For example:

DWORD CMyCtrl::GetControlFlags()
{
    return COleControl::GetControlFlags() & ~clipPaintDC;
}

The code to remove this flag is automatically generated if you select the Unclipped Device Context option on the Advanced ActiveX Features page, when creating your control with ControlWizard.

If you are using windowless activation, this optimization has no effect.


Optimizing Control Drawing

Home | Overview | How Do I | FAQ | Tutorial | Sample

When a control is instructed to draw itself into a container-supplied device context, it typically selects GDI objects (such as pens, brushes, and fonts) into the device context, performs its drawing operations, and restores the previous GDI objects. If the container has multiple controls that are to be drawn into the same device context, and each control selects the GDI objects it requires, time can be saved if the controls do not individually restore previously selected objects. After all of the controls have been drawn, the container can automatically restore the original objects.

To detect whether a container supports this technique, a control can call the COleControl::IsOptimizedDraw member function. If this function returns TRUE, the control can skip the normal step of restoring the previously selected objects.

Consider a control that has the following (unoptimized) OnDraw function:

void CMyCtrl::OnDraw(CDC* pdc, CRect& rcBounds, CRect& rcInvalid)
{
    CPen pen(PS_SOLID, 0, TranslateColor(GetForeColor()));
    CBrush brush(TranslateColor(GetBackColor()));
    CPen* pPenSave = pdc->SelectObject(&pen);
    CBrush* pBrushSave = pdc->SelectObject(&brush);
    Rectangle(rcBounds);
    pdc->SelectObject(pPenSave);
    pdc->SelectObject(pBrushSave);
}

The pen and brush in this example are local variables, meaning their destructors will be called when they go out of scope (when the OnDraw function ends). The destructors will attempt to delete the corresponding GDI objects. But they should not be deleted if you plan to leave them selected into the device context upon returning from OnDraw.

To prevent the CPen and CBrush objects from being destroyed when OnDraw finishes, store them in member variables instead of local variables. In the control's class declaration, add declarations for two new member variables:

class CMyCtrl : public COleControl
{
    .
    .
    .
    CPen m_pen;
    CBrush m_brush;
}

Then, the OnDraw function can be rewritten as follows:

void CMyCtrl::OnDraw(CDC* pdc, CRect& rcBounds, CRect& rcInvalid)
{
    if (m_pen.m_hObject == NULL)
        m_pen.CreatePen(PS_SOLID, 0, TranslateColor(GetForeColor()));
    if (m_Brush.m_hObject == NULL)
        m.Brush.CreateSolidBrush(TranslateColor(GetBackColor()));
    CPen* pPenSave = pdc->SelectObject(&m_pen);
    CBrush* pBrushSave = pdc->SelectObject(&m_brush);
    Rectangle(rcBounds);
    pdc->SelectObject(pPenSave);
    pdc->SelectObject(pBrushSave);
}

This approach avoids creation of the pen and brush every time OnDraw is called. The speed improvement comes at the cost of maintaining additional instance data.

If the ForeColor or BackColor property changes, the pen or brush needs to be created again. To do this, override the OnForeColorChanged and OnBackColorChanged member functions:

void CMyCtrl::OnForeColorChanged()
{
    m_pen.DeleteObject();
}

void CMyCtrl::OnBackColorChanged()
{
    m_brush.DeleteObject();
}

Finally, to eliminate unnecessary SelectObject calls, modify OnDraw as follows:

void CMyCtrl::OnDraw(CDC* pdc, CRect& rcBounds, CRect& rcInvalid)
{
    if (m_pen.m_hObject == NULL)
        m_pen.CreatePen(PS_SOLID, 0, TranslateColor(GetForeColor()));
    if (m_Brush.m_hObject == NULL)
        m.Brush.CreateSolidBrush(TranslateColor(GetBackColor()));
    CPen* pPenSave = pdc->SelectObject(&m_pen);
    CBrush* pBrushSave = pdc->SelectObject(&m_brush);
    Rectangle(rcBounds);
    if (! IsOptimizedDraw())
    {
        pdc->SelectObject(pPenSave);
        pdc->SelectObject(pBrushSave);
    }
}

See Also COleControl, Serialization, Basic Components of an ActiveX Control, Create a Program with the MFC ActiveX ControlWizard, ActiveX Controls: Painting an ActiveX Control


ActiveX Controls: Painting an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article describes the ActiveX control painting process and how you can alter paint code to optimize the process. (See Optimizing Control Drawing for techniques on how to optimize drawing by not having controls individually restore previously selected GDI objects. After all of the controls have been drawn, the container can automatically restore the original objects.)

Examples in this article are from a control created by ControlWizard with default settings. For more information on creating a skeleton control application using ControlWizard, see the article Createa Program with the MFC ActiveX ControlWizard.

The following topics are covered:

  • The overall process for painting a control and the code created by ControlWizard to support painting

  • How to optimize the painting process

  • How to paint your control using metafiles

The Painting Process of an ActiveX Control

When ActiveX controls are initially displayed or are redrawn, they follow a painting process similar to other applications developed using MFC, with one important distinction: ActiveX controls can be in an active or an inactive state.

An active control is represented in an ActiveX control container by a child window. Like other windows, it is responsible for painting itself when a WM_PAINT message is received. The control’s base class, COleControl, handles this message in its OnPaint function. This default implementation calls the OnDraw function of your control.

An inactive control is painted differently. When the control is inactive, its window is either invisible or nonexistent, so it can not receive a paint message. Instead, the control container directly calls the OnDraw function of the control. This differs from an active control’s painting process in that the OnPaint member function is never called.

As discussed in the preceding paragraphs, how an ActiveX control is updated depends on the state of the control. However, because the framework calls the OnDraw member function in both cases, you add the majority of your painting code in this member function.

The OnDraw member function handles control painting. When a control is inactive, the control container calls OnDraw, passing the device context of the control container and the coordinates of the rectangular area occupied by the control.

The rectangle passed by the framework to the OnDraw member function contains the area occupied by the control. If the control is active, the upper-left corner is (0, 0) and the device context passed is for the child window that contains the control. If the control is inactive, the upper-left coordinate is not necessarily (0, 0) and the device context passed is for the control container containing the control.

Note It is important that your modifications to OnDraw do not depend on the rectangle’s upper-left point being equal to (0, 0) and that you draw only inside the rectangle passed to OnDraw. Unexpected results can occur if you draw beyond the rectangle’s area.

The default implementation provided by ControlWizard in the control implementation file (.CPP), shown below, paints the rectangle with a white brush and fills the ellipse with the current background color.

void CSampleCtrl::OnDraw( CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid )
{
    pdc->FillRect( rcBounds,
        CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
    pdc->Ellipse( rcBounds );
}

Note When painting a control, you should not make assumptions about the state of the device context that is passed as the pdc parameter to the OnDraw function. Occasionally the device context is supplied by the container application and will not necessarily be initialized to the default state. In particular, explicitly select the pens, brushes, colors, fonts, and other resources that your drawing code depends upon.

Optimizing Your Paint Code

Once the control is successfully painting itself, the next step is to optimize the OnDraw function.

The default implementation of ActiveX control painting simply paints the entire control area. This is sufficient for simple controls, but in many cases repainting the control would be faster if only the portion that needed updating was repainted, instead of the entire control.

The OnDraw function provides an easy method of optimization by passing rcInvalid, the rectangular area of the control that needs redrawing. Use this area, usually smaller than the entire control area, to speed up the painting process.

Painting Your Control Using Metafiles

In most cases the pdc parameter to the OnDraw function points to a screen device context (DC). However, when printing images of the control or during a print preview session, the DC received for rendering is a special type called a “metafile DC”. Unlike a screen DC, which immediately handles requests sent to it, a metafile DC stores requests to be played back at a later time. Some container applications, such as Microsoft Access 2.0, may also choose to render the control image using a metafile DC when in design mode.

Drawing requests can be made by the container through two interface functions: IViewObject::Draw (this function can also be called for non-metafile drawing) and IDataObject::GetData. When a metafile DC is passed as one of the parameters, the MFC framework makes a call to COleControl::OnDrawMetafile. Because this is a virtual member function, override this function in the control class to do any special processing. The default behavior calls COleControl::OnDraw.

To make sure the control can be drawn in both screen and metafile device contexts, you must use only member functions that are supported in both a screen and a metafile DC. Be aware that the coordinate system may not be measured in pixels.

Because the default implementation of OnDrawMetafile calls the control’s OnDraw function, use only member functions that are suitable for both a metafile and a screen device context, unless you override OnDrawMetafile. The following lists the subset of CDC member functions that can be used in both a metafile and a screen device context. For more information on these functions, see class CDC in the Class Library Reference.

Arc | Pie | SetMapMode
Chord | Polygon | SetMapperFlags
Ellipse | Polyline | SetPixel
Escape | PolyPolygon | SetPolyFillMode
BibBlt | RealizePalette | SetROP2
ExcludeClipRect | RestoreDC | SetStretchBltMode
ExtTextOut | RoundRect | SetTextColor
FloodFill | SaveDC | SetTextJustification
IntersectClipRect | ScaleViewportExt | SetViewportExt
LineTo | ScaleWindowExt | SetViewportOrg
MoveTo | SelectClipRgn | SetWindowExt
OffsetClipRgn | SelectObject | SetWindowORg
OffsetViewportOrg | SelectPalette | StretchBlt
OffsetWindowOrg | SetBkColor | TextOut
PatBlt | SetBkMode |

In addition to CDC member functions, there are several other functions that are compatible in a metafile DC. These include CPalette::AnimatePalette, CFont::CreateFontIndirect, and three member functions of CBrush: CreateBrushIndirect, CreateDIBPatternBrush, and CreatePatternBrush.

Another point to consider when using a metafile DC is that the coordinate system may not be measured in pixels. For this reason, all your drawing code should be adjusted to fit in the rectangle passed to OnDraw in the rcBounds parameter. This prevents accidental painting outside the control because rcBounds represents the size of the control’s window.

Once you have implemented metafile rendering for the control, use Test Container to test the metafile.

To test the control’s metafile using Test Container

  1. On the Tools menu, click ActiveX Control Test Container.

  2. On the Test Container’s Edit menu, click Insert ActiveX Control.

  3. In the Insert ActiveX Control box, select the desired control and click OK.

    The control will appear in Test container.

  4. On the Control menu, click Draw Metafile.

    A separate window appears in which the metafile is displayed. You can change the size of this window to see how scaling affects the control’s metafile. You can close this window at any time.


ActiveX Controls: Events

Home | Overview | How Do I | FAQ | Tutorial | Sample

ActiveX controls use events to notify a container that something has happened to the control. Common examples of events include clicks on the control, data entered using the keyboard, and changes in the control’s state. When these actions occur, the control fires an event to alert the container.

MFC supports two kinds of events: stock and custom. Stock events are those events that class COleControl handles automatically. For a complete list of stock events, see the article ActiveX Controls: Adding Stock Events to an ActiveX Control. Custom events allow a control the ability to notify the container when an action specific to that control occurs. Some examples would be a change in the internal state of a control or receipt of a certain window message.

For your control to fire events properly, your control class must map each event of the control to a member function that should be called when the related event occurs. This mapping mechanism (called an event map) centralizes information about the event and allows ClassWizard to easily access and manipulate the control’s events. This event map is declared by the following macro, located in the header (.H) file of the control class declaration:

DECLARE_EVENT_MAP()

The following figure shows the ActiveX Events tab in ClassWizard. You use this tab to add custom and stock events.

The ActiveX Events tab

Once the event map has been declared, it must be defined in your control’s implementation (.CPP) file. The following lines of code define the event map, allowing your control to fire specific events:

BEGIN_EVENT_MAP(CSampleCtrl, COleControl)
//{{AFX_EVENT_MAP(CSampleCtrl)
...
//}}AFX_EVENT_MAP
END_EVENT_MAP()

If you use ControlWizard to create the project, it automatically adds these lines. If you do not use ControlWizard, you must add these lines manually.

With ClassWizard, you can add stock events supported by class COleControl or custom events that you define. For each new event, ClassWizard automatically adds the proper entry to the control’s event map and the control’s .ODL file.

Two other articles discuss events in detail:

  • ActiveX Controls: Adding Stock Events to an ActiveX Control

  • ActiveX Controls: Adding Custom Events to an ActiveX Control

See Also ActiveX Controls: Methods, COleControl


ActiveX Controls: Adding Stock Events to an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

Stock events differ from custom events in that they are automatically fired by class COleControl. COleControl contains predefined member functions that fire events resulting from common actions. Some common actions implemented by COleControl include single- and double-clicks on the control, keyboard events, and changes in the state of the mouse buttons. Event map entries for stock events are always preceded by the EVENT_STOCK prefix.

Stock Events Supported by ClassWizard

The COleControl class provides nine stock events, listed in the following table. You can specify the events you want in your control in the ActiveX Events tab in ClassWizard.

Stock Events

Event | Firing function | Comments
Click | void FireClick( ) | Fired when the control captures the mouse, any BUTTONUP (left, middle, or right) message is received, and the button is released over the control. The stock MouseDown and MouseUp events occur before this event. Event map entry: EVENT_STOCK_CLICK( )
DblClick | void FireDblClick( ) | Similar to Click but fired when a BUTTONDBLCLK message is received. Event map entry: EVENT_STOCK_DBLCLICK( )
Error | void FireError( SCODE scode, LPCSTR lpszDescription, UINT nHelpID = 0 ) | Fired when an error occurs within your ActiveX control outside of the scope of a method call or property access. Event map entry: EVENT_STOCK_ERROREVENT( )
KeyDown | void FireKeyDown( short nChar, short nShiftState ) | Fired when a WM_SYSKEYDOWN or WM_KEYDOWN message is received. Event map entry: EVENT_STOCK_KEYDOWN( )
KeyPress | void FireKeyPress( short* pnChar ) | Fired when a WM_CHAR message is received. Event map entry: EVENT_STOCK_KEYPRESS( )
KeyUp | void FireKeyUp( short nChar, short nShiftState ) | Fired when a WM_SYSKEYUP or WM_KEYUP message is received. Event map entry: EVENT_STOCK_KEYUP( )
MouseDown | void FireMouseDown( short nButton, short nShiftState, float x, float y ) | Fired if any BUTTONDOWN (left, middle, or right) is received. The mouse is captured immediately before this event is fired. Event map entry: EVENT_STOCK_MOUSEDOWN( )
MouseMove | void FireMouseMove( short nButton, short nShiftState, float x, float y ) | Fired when a WM_MOUSEMOVE message is received. Event map entry: EVENT_STOCK_MOUSEMOVE( )
MouseUp | void FireMouseUp( short nButton, short nShiftState, float x, float y ) | Fired if any BUTTONUP (left, middle, or right) is received. The mouse capture is released before this event is fired. Event map entry: EVENT_STOCK_MOUSEUP( )
ReadyStateChange | void FireReadyStateChange( ) | Fired when a control transitions to the next ready state due to the amount of data received. Event map entry: EVENT_STOCK_READYSTATECHANGE( )

Adding a Stock Event Using ClassWizard

Adding stock events requires less work than adding custom events because the firing of the actual event is handled automatically by the base class, COleControl. The following procedure adds a stock event to a control that was developed using ControlWizard. The event, called KeyPress, fires when a key is pressed and the control is active. This procedure can also be used to add other stock events. Simply substitute the desired stock event name for KeyPress.

To add the KeyPress stock event using ClassWizard

  1. Load your control’s project.

  2. On the View menu, click ClassWizard.

  3. Click the ActiveX Events tab.

  4. Select the name of your control class from the Class Name box.

  5. Click Add Event.

  6. In the External Name box, click KeyPress.

  7. Click OK.

  8. Click OK again to confirm your choices and exit ClassWizard.

ClassWizard Changes for Stock Events

Because stock events are handled by the control’s base class, ClassWizard does not change your class declaration in any way. It simply adds the event to the control’s event map and makes an entry in its .ODL file. The following line is added to the control’s event map, located in the control class implementation (.CPP) file:

EVENT_STOCK_KEYPRESS()

Adding this code fires a KeyPress event when a WM_CHAR message is received and the control is active. The KeyPress event can be fired at other times by calling its firing function (for example, FireKeyPress) from within the control code.

ClassWizard adds the following line of code to the control’s .ODL file:

[id(DISPID_KEYPRESS)] void KeyPress(short* KeyAscii);

This line associates the KeyPress event with its standard dispatch ID and allows the container to anticipate the KeyPress event.

See Also ActiveX Controls: Methods, COleControl


ActiveX Controls: Adding Custom Events to an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

Custom events differ from stock events in that they are not automatically fired by class COleControl. A custom event recognizes a certain action, determined by the control developer, as an event. The event map entries for custom events are represented by the EVENT_CUSTOM macro. The following section implements a custom event for an ActiveX control project that was created using ControlWizard.

Adding a Custom Event with ClassWizard

The following procedure adds a specific custom event, ClickIn. You can use this procedure to add other custom events. Simply substitute your custom event name and its parameters for the ClickIn event name and parameters.

To add the ClickIn custom event using ClassWizard

  1. Load your control’s project.

  2. On the View menu, click ClassWizard.

  3. Click the ActiveX Events tab.

  4. Select the name of the control class from the Class name box.

  5. Click Add Event.

  6. In the External name box, type ClickIn.

  7. In the Internal name box, type the name of the event’s firing function. For this example, use the default value provided by ClassWizard (FireClickIn).

  8. Add a parameter, called xCoord (type OLE_XPOS_PIXELS), using the Parameter List grid control.

  9. Add a second parameter, called yCoord (type OLE_YPOS_PIXELS), using the Parameter List grid control.

  10. Click OK to close Add Event.

  11. Click OK again to confirm your choices and close ClassWizard.

ClassWizard Changes for Custom Events

When you add a custom event, ClassWizard makes changes to the control class .H, .CPP, and .ODL files. The following code samples are specific to the ClickIn event.

The following lines are added to the header (.H) file of your control class:

void FireClickIn(OLE_XPOS_PIXELS xCoord, OLE_YPOS_PIXELS yCoord)
    {FireEvent(eventidClickIn,EVENT_PARAM(VTS_XPOS_PIXELS  VTS_YPOS_PIXELS), xCoord, yCoord);}

This code declares an inline function called FireClickIn that calls COleControl::FireEvent with the ClickIn event and parameters you defined using ClassWizard.

In addition, the following line is added to the event map for the control, located in the implementation (.CPP) file of your control class:

EVENT_CUSTOM("ClickIn", FireClickIn, VTS_XPOS_PIXELS  VTS_YPOS_PIXELS)

This code maps the event ClickIn to the inline function FireClickIn, passing the parameters you defined using ClassWizard.

Finally, the following line is added to your control’s .ODL file:

[id(1)] void ClickIn(OLE_XPOS_PIXELS xCoord, OLE_YPOS_PIXELS yCoord);

This line assigns the ClickIn event a specific ID number, taken from the event’s position in the ClassWizard event list. The entry in the event list allows a container to anticipate the event. For example, it might provide handler code to be executed when the event is fired.

Calling FireClickIn

Now that you have added the ClickIn custom event using ClassWizard, you must decide when this event is to be fired. You do this by calling FireClickIn when the appropriate action occurs. For this discussion, the control uses the InCircle function inside a WM_LBUTTONDOWN message handler to fire the ClickIn event when a user clicks inside a circular or elliptical region. The following procedure adds the WM_LBUTTONDOWN handler.

To add a message handler with ClassWizard

  1. Load your control’s project.

  2. On the View menu, click ClassWizard.

  3. Click the Message Maps tab.

  4. In the Object IDs box, select the control class name, in this case, CSampleCtrl.

  5. In the Messages box, select the message you would like to handle. For this example, select WM_LBUTTONDOWN.

  6. Click Add Function to add the handler function to your application.

  7. Click Edit Code to jump to the location of the message handler, or click OK to confirm your choice.

The following code sample calls the InCircle function every time the left mouse button is clicked within the control window. This sample can be found in the WM_LBUTTONDOWN handler function, OnLButtonDown, in the Circle sample described in Tutorials. For more information on this function, see Hit Testing, also in Tutorials.

void CSampleCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
    if (InCircle(point))
        FireClickIn(point.x, point.y);

    COleControl::OnLButtonDown(nFlags, point);
}

Note When ClassWizard creates message handlers for mouse button actions, a call to the same message handler of the base class is automatically added. Do not remove this call. If your control uses any of the stock mouse messages, the message handlers in the base class must be called to ensure that mouse capture is handled properly.

In the following example, the event fires only when the click occurs inside a circular or elliptical region within the control. To achieve this behavior, you can place the InCircle function, taken from Hit Testing of Tutorials, in your control’s implementation (.CPP) file:

BOOL CSampleCtrl::InCircle(CPoint& point)
{
    CRect rc;
    GetClientRect(rc);
    // Determine radii
    double a = (rc.right - rc.left) / 2;
    double b = (rc.bottom - rc.top) / 2;

    // Determine x, y
    double x = point.x - (rc.left + rc.right) / 2;
    double y = point.y - (rc.top + rc.bottom) / 2;

    // Apply ellipse formula
    return ((x * x) / (a * a) + (y * y) / (b * b) <= 1);
}

You will also need to add the following declaration of the InCircle function to your control’s header (.H) file:

BOOL InCircle( CPoint& point );

Custom Events with Stock Names

You can create custom events with the same name as stock events, however you can not implement both in the same control. For example, you might want to create a custom event called Click that does not fire when the stock event Click would normally fire. You could then fire the Click event at any time by calling its firing function.

The following procedure adds a custom Click event.

To add a custom event that uses a stock event name

  1. Load your control’s project.

  2. On the View menu, click ClassWizard.

  3. Click the ActiveX Events tab.

  4. Click Add Event.

  5. In the External name box, select a stock event name. For this example, select Click.

  6. In the Implementation box, click Custom.

  7. Click OK.

  8. Click OK again to confirm your choices and exit ClassWizard.

  9. Call FireClick at appropriate places in your code.

See Also ActiveX Controls: Methods, COleControl


ActiveX Controls: Methods

Home | Overview | How Do I | FAQ | Tutorial | Sample

An ActiveX control fires events to communicate between itself and its control container. A container can also communicate with a control by means of methods and properties. Methods and properties provide an exported interface for use by other applications, such as Automation clients and ActiveX control containers. For more information on ActiveX control properties, see the article ActiveX Controls: Properties.

Methods are similar in usage and purpose to the member functions of a C++ class. There are two types of methods your control can implement: stock and custom. Similar to stock events, stock methods are those methods for which COleControl provides an implementation. For more information on stock methods, see the article ActiveX Controls: Adding Stock Methods to an ActiveX Control. Custom methods, defined by the developer, allow additional customization of the control. For more information, see the article ActiveX Controls: Adding Custom Methods to an ActiveX Control.

The Microsoft Foundation Class Library (MFC) implements a mechanism that allows your control to support stock and custom methods. The first part is class COleControl. Derived from CWnd, COleControl member functions support stock methods that are common to all ActiveX controls. The second part of this mechanism is the dispatch map. A dispatch map is similar to a message map; however, instead of mapping a function to a Windows message ID, a dispatch map maps virtual member functions to IDispatch IDS.

For a control to support various methods properly, its class must declare a dispatch map. This is accomplished by the following line of code located in control class header (.H) file:

DECLARE_DISPATCH_MAP()

The main purpose of the dispatch map is to establish the relationship between the method names used by an external caller (such as the container) and the member functions of the control’s class that implement the methods. Once the dispatch map has been declared, it needs to be defined in the control’s implementation (.CPP) file. The following lines of code define the dispatch map:

BEGIN_DISPATCH_MAP(CSampleCtrl, COleControl)
   //{{AFX_DISPATCH_MAP(CSampleCtrl)
   ...
   //}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()

If ControlWizard was used to create the project, these lines were added automatically. If ControlWizard was not used, you must add these lines manually. The two comment lines allow ClassWizard to automatically insert macros into the dispatch map.

The following articles discuss Methods in detail:

  • ActiveX Controls: Adding Stock Methods to an ActiveX Control

  • ActiveX Controls: Adding Custom Methods to an ActiveX Control

  • ActiveX_Controls: Returning Error Codes From a Method


ActiveX Controls: Adding Stock Methods to an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

A stock method differs from a custom method in that it is already implemented by class COleControl. For example, COleControl contains a predefined member function supports the Refresh method for your control. The dispatch map entry for this stock method is DISP_STOCKFUNC_REFRESH.

COleControl supports two stock methods: DoClick and Refresh. Refresh is invoked by the control’s user to immediately update the control’s appearance; DoClick is invoked to fire the control’s Click event.

Method | Dispatch Map Entry | Comment
DoClick | DISP_STOCKPROP_DOCLICK( ) | Fires a Click event.
Refresh | DISP_STOCKPROP_REFRESH( ) | Immediately updates the control’s appearance.

Adding a Stock Method Using ClassWizard

Adding a stock method is simple using ClassWizard. The following procedure demonstrates adding the Refresh method to a control created using ControlWizard.

To add the stock Refresh method using ClassWizard

  1. Load your control’s project.

  2. On the View menu, click ClassWizard.

  3. Choose the Automation tab.

  4. Click the control class in the Class name box.

  5. Click Add Method.

  6. In the External name box, click Refresh.

  7. Click OK.

  8. Click OK to confirm your choices and close ClassWizard.

The following figure shows the Add Method dialog box of ClassWizard.

The Add Method Dialog Box

ClassWizard Changes for Stock Methods

Because the stock Refresh method is supported by the control’s base class, ClassWizard does not change the control’s class declaration in any way. It simply adds an entry for the method to the control’s dispatch map and to its .ODL file. The following line is added to the control’s dispatch map, located in its implementation (.CPP) file:

DISP_STOCKFUNC_REFRESH( )

This makes the Refresh method available to the control’s users.

The following line is added to the control’s .ODL file:

[id(DISPID_REFRESH)] void Refresh();

This line assigns the Refresh method a specific ID number.


ActiveX Controls: Adding Custom Methods to an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

Custom methods differ from stock methods in that they are not already implemented by COleControl. You must supply the implementation for each custom method you add to your control.

An ActiveX control user can call a custom method at any time to perform control-specific actions. The dispatch map entry for custom methods is of the form DISP_FUNCTION.

Adding a Custom Method With ClassWizard

The following procedure demonstrates adding the custom method PtInCircle to an ActiveX control’s skeleton code. PtInCircle determines whether the coordinates passed to the control are inside or outside the circle. This same procedure can also be used to add other custom methods. Simply substitute your custom method name and its parameters for the PtInCircle method name and parameters. (This example uses the InCircle function from the article Events. For more information on this function, see the article ActiveX Controls: Adding Custom Events to an ActiveX Control.)

To add the PtInCircle custom method using ClassWizard

  1. Load the control’s project.

  2. On the View menu, click ClassWizard.

  3. Click the Automation tab.

  4. Select the control’s class from the Class Name box.

  5. Click Add Method.

  6. In the External name box, type PtInCircle.

  7. In the Internal name box, type the name of the method’s internal function or use the default value provided by ClassWizard (in this case, PtInCircle).

  8. In the Return Type box, click BOOL for the method’s return type.

  9. Using the Parameter List grid control, add a parameter, called xCoord (type OLE_XPOS_PIXELS).

  10. Using the Parameter List grid control, add a second parameter, called yCoord (type OLE_YPOS_PIXELS).

  11. Click OK to close the Add Method dialog box.

  12. Click OK to confirm your choices and close ClassWizard.

ClassWizard Changes for Custom Methods

When you add a custom method, ClassWizard makes some changes to the control class header (.H) and implementation (.CPP) files. The following line is added to the dispatch map declaration in the control class header (.H) file:

afx_msg BOOL PtInCircle(long xCoord, long yCoord);

This code declares a dispatch method handler called PtinCircle. This function can be called by the control user using the external name PtInCircle.

The following line is added to the control’s .ODL file:

[id(1)] boolean PtInCircle(OLE_XPOS_PIXELS xCoord, OLE_YPOS_PIXELS yCoords);

This line assigns the PtInCircle method a specific ID number, taken from the method’s position in ClassWizard’s methods and properties list. Because ClassWizard was used to add the custom method, the entry for it was added automatically to the project’s .ODL file.

In addition, the following line, located in the implementation (.CPP) file of the control class, is added to the control’s dispatch map:

DISP_FUNCTION(CSampleCtrl, "PtInCircle", PtInCircle, VT_BOOL, VTS_I4 VTS_I4)

The DISP_FUNCTION macro maps the method PtInCircle to the control’s handler function, PtInCircle, declares the return type to be BOOL, and declares two parameters of type short to be passed to PtInCircle.

Finally, ClassWizard adds the stub function CSampleCtrl::PtinCircle to the bottom of the control’s implementation (.CPP) file. For PtinCircle to function as stated previously, it must be modified as follows:

BOOL CSampleCtrl::PtInCircle(short xCoord, short yCoord)
{
    return InCircle(CPoint(xCoord, yCoord));
}


ActiveX Controls: Returning Error Codes From a Method

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article describes how to return error codes from an ActiveX control method.

To indicate that an error has occurred within a method, you should use the COleControl::ThrowError member function, which takes an SCODE (status code) as a parameter. You can use a predefined SCODE or define one of your own.

Note ThrowError is meant to be used only as a means of returning an error from within a property’s Get or Set function or an automation Method. These are the only times that the appropriate exception handler will be present on the stack.

Helper functions exist for the most common predefined SCODEs, such as COleControl::SetNotSupported, COleControl::GetNotSupported, and COleControl::SetNotPermitted.

For a list of predefined SCODEs and instructions on defining custom SCODEs, see the section Handling Errors in Your ActiveX Control in ActiveX Controls: Advanced Topics.

For more information on reporting exceptions in other areas of your code, see COleControl::FireError and the section Handling Errors in Your ActiveX Control in ActiveX Controls: Advanced Topics.


ActiveX Controls: Properties

Home | Overview | How Do I | FAQ | Tutorial | Sample

An ActiveX control fires events to communicate with its control container. The container, in return, uses methods and properties to communicate with the control. Methods and properties are similar in use and purpose, respectively, to member functions and member variables of a C++ class. Properties are data members of the ActiveX control that are exposed to any container. Properties provide an interface for applications that contain ActiveX controls, such as Automation clients and ActiveX control containers.

For more information on ActiveX control methods, see the article ActiveX Controls: Methods.

ActiveX controls can implement both stock and custom methods and properties. Class COleControl provides an implementation for stock properties. (For a complete list of stock properties, see the article ActiveX Controls: Adding Stock Properties.) Custom properties, defined by the developer, add specialized capabilities to an ActiveX control. For more information, see ActiveX Controls: Adding Custom Properties.

Both custom and stock properties, like methods, are supported by a mechanism that consists of a dispatch map that handles properties and methods and existing member functions of the COleControl class. In addition, these properties can have parameters that the developer uses to pass extra information to the control.

The following articles discuss ActiveX control properties in more detail:

  • ActiveX Controls: Adding Stock Properties

  • ActiveX Controls: Adding Custom Properties

  • ActiveX Controls: Advanced Property Implementation

  • ActiveX Controls: Accessing Ambient Properties


ActiveX Controls: Adding Stock Properties

Home | Overview | How Do I | FAQ | Tutorial | Sample

Stock properties differ from custom properties in that they are already implemented by the class COleControl. COleControl contains predefined member functions that support common properties for the control. Some common properties include the control’s caption and the foreground and background colors. For information on other stock properties, see Stock Properties Supported by ClassWizard later in this article. The dispatch map entries for stock properties are always prefixed by DISP_STOCKPROP.

This article describes how to add a stock property (in this case, Caption) to an ActiveX control using ClassWizard and explains the resulting code modifications. Topics include:

  • Using ClassWizard to add a stock property

  • ClassWizard changes for stock properties

  • Stock properties supported by ClassWizard

  • Stock properties and notification

  • Color properties

Note Visual Basic custom (VBX) controls typically have properties such as Top, Left, Width, Height, Align, Tag, Name, TabIndex, TabStop, and Parent. ActiveX control containers, however, are responsible for implementing these control properties and therefore ActiveX controls should not support these properties.

Using ClassWizard to Add a Stock Property

Adding stock properties requires less code than adding custom properties because support for the property is handled automatically by COleControl. The following procedure demonstrates adding the stock Caption property to an ActiveX control framework. This same procedure can also be used to add other stock properties. Simply substitute the desired stock property name for Caption.

To add the stock Caption property using ClassWizard

  1. Load your control’s project.

  2. On the View menu, click ClassWizard.

  3. Click the Automation tab.

  4. Select the control’s class from the Class name box.

  5. Click Add Property.

  6. In the External name box, click Caption.

    Note that in the Implementation group, Stock is automatically selected.

  7. Click OK to close the Add Property box.

  8. Click OK to confirm your choices and close ClassWizard.

ClassWizard Changes for Stock Properties

Because COleControl supports stock properties, ClassWizard does not change the class declaration in any way; it simply adds the property to the dispatch map. ClassWizard adds the following line to the dispatch map of the control, which is located in the implementation (.CPP) file:

DISP_STOCKPROP_CAPTION( )

The following line is added to your control’s Object Description (.ODL) file:

[id(DISPID_CAPTION), bindable, requestedit] BSTR Caption;

This line assigns the Caption property a specific ID. Notice that the property is bindable and will request permission from the database before modifying the value.

This makes the Caption property available to users of your control. To use the value of a stock property, access a member variable or member function of the COleControl base class. For more information on these member variables and member functions, see Stock Properties Supported by ClassWizard.

Stock Properties Supported by ClassWizard

The COleControl class provides nine stock properties. You can specify the properties you want in the control in the Automation tab of the MFC ClassWizard dialog box.

Property | Dispatch map entry | How to access value
Appearance | DISP_STOCKPROP_APPEARANCE( ) | Value accessible as m_sAppearance.
BackColor | DISP_STOCKPROP_BACKCOLOR( ) | Value accessible by calling GetBackColor.
BorderStyle | DISP_STOCKPROP_BORDERSTYLE( ) | Value accessible as m_sBorderStyle.
Caption | DISP_STOCKPROP_CAPTION( ) | Value accessible by calling InternalGetText.
Enabled | DISP_STOCKPROP_ENABLED( ) | Value accessible as m_bEnabled.
Font | DISP_STOCKPROP_FONT( ) | See the article ActiveX Controls: Using Fonts in an ActiveX Control for usage.
ForeColor | DISP_STOCKPROP_FORECOLOR( ) | Value accessible by calling GetForeColor.
hWnd | DISP_STOCKPROP_HWND( ) | Value accessible as m_hWnd.
Text | DISP_STOCKPROP_TEXT( ) | Value accessible by calling InternalGetText. This property is the same as Caption, except for the property name.

Stock Properties and Notification

Most of the stock properties have notification functions that can be overridden. For example, whenever the BackColor property is changed, the OnBackColorChanged function (a member function of the control class) is called. The default implementation (in COleControl) calls InvalidateControl. Override this function if you want to take additional actions in response to this situation.

Color Properties

You can use the stock ForeColor and BackColor properties, or your own custom color properties, when painting the control. To use a color property, call the COleControl::TranslateColor member function. The parameters of this function are the value of the color property and an optional palette handle. The return value is a COLORREF value that can be passed to GDI functions, such as SetTextColor and CreateSolidBrush.

The color values for the stock ForeColor and BackColor properties are accessed by calling either the GetForeColor or the GetBackColor function, respectively.

The following example demonstrates using these two color properties when painting a control. It initializes a temporary COLORREF variable and a CBrush object with calls to TranslateColor: one using the ForeColor property and the other using the BackColor property. A temporary CBrush object is then used to paint the control’s rectangle, and the text color is set using the ForeColor property.

   CBrush bkBrush(TranslateColor(GetBackColor()));
   COLORREF clrFore = TranslateColor(GetForeColor());
   pdc->FillRect( rcBounds, &bkbrush );
   pdc->SetTextColor( clrFore );
   pdc->DrawText( InternalGetText(), -1, rcBounds, DT_SINGLELINE | DT_CENTER | DT_VCENTER );

See Also ActiveX Controls: Properties, ActiveX Controls: Methods, COleControl


ActiveX Controls: Adding Custom Properties

Home | Overview | How Do I | FAQ | Tutorial | Sample

Custom properties differ from stock properties in that custom properties are not already implemented by the COleControl class. A custom property is used to expose a certain state or appearance of an ActiveX control to a programmer using the control.

This article describes how to add a custom property to the ActiveX control using ClassWizard and explains the resulting code modifications. Topics include:

  • Using ClassWizard to add a custom property

  • ClassWizard changes for custom properties

Custom properties come in four varieties of implementation: Member Variable, Member Variable with Notification, Get/Set Methods, and Parameterized.

  • Member Variable Implementation

    This implementation represents the property’s state as a member variable in the control class. Use the Member Variable implementation when it is not important to know when the property value changes. Of the three types, this implementation creates the least amount of support code for the property. The dispatch map entry macro for member variable implementation is DISP_PROPERTY. For a detailed example of this implementation, see Adding Special Effects, in Tutorials.

  • Member Variable with Notification Implementation

    This implementation consists of a member variable and a notification function created by ClassWizard. The notification function is automatically called by the framework after the property value changes. Use the Member Variable with Notification implementation when you need to be notified after a property value has changed. This implementation requires more time because it requires a function call. The dispatch map entry macro for this implementation is DISP_PROPERTY_NOTIFY. For a detailed example of this implementation, see Adding a Custom Notification Property in Tutorials.

  • Get/Set Methods Implementation

    This implementation consists of a pair of member functions in the control class. The Get/Set Methods implementation automatically calls the Get member function when the control’s user requests the current value of the property and the Set member function when the control’s user requests that the property be changed. Use this implementation when you need to compute the value of a property during run time, validate a value passed by the control’s user before changing the actual property, or implement a read- or write-only property type. The dispatch map entry macro for this implementation is DISP_PROPERTY_EX. The following section, Using ClassWizard to Add a Custom Property, uses the CircleOffset custom property to demonstrate this implementation.

  • Parameterized Implementation

    Parameterized implementation is supported by ClassWizard. A parameterized property (sometimes called a property array) can be used to access a set of values through a single property of your control. The dispatch map entry macro for this implementation is DISP_PROPERTY_PARAM. For more information on implementing this type, see Implementing a Parameterized Property in the article “ActiveX Controls: Advanced Topics”.

Using ClassWizard to Add a Custom Property

The following procedure demonstrates adding a custom property, CircleOffset, which uses the Get/Set Methods implementation. The CircleOffset custom property allows the control’s user to offset the circle from the center of the control’s bounding rectangle. The procedure for adding custom properties with an implementation other than Get/Set Methods is very similar.

This same procedure can also be used to add other custom properties you desire. Simply substitute your custom property name for the CircleOffset property name and parameters.

To add the CircleOffset custom property using ClassWizard

  1. Load your control’s project.

  2. On the View menu, click ClassWizard.

  3. Click the Automation tab.

  4. Select the control’s class from the Class Name box.

  5. Click Add Property.

  6. In the External Name box, type CircleOffset.

  7. In the Implementation box, click Get/Set Methods.

  8. In the Type box, select short for the property’s type.

  9. Type unique names for your Get and Set Functions, or accept the default names.

  10. Click OK to close the Add Property dialog box.

  11. Click OK to confirm your choices and close ClassWizard.

ClassWizard Changes for Custom Properties

When you add the CircleOffset custom property, ClassWizard makes changes to the header (.H) and the implementation (.CPP) files of the control class.

The following lines are added to the .H file to declare two functions called GetCircleOffset and SetCircleOffset:

afx_msg short GetCircleOffset( );
afx_msg void SetCircleOffset(short nNewValue);

The following line is added to your control’s .ODL file:

[id(1)] short CircleOffset;

This line assigns the CircleOffset property a specific ID number, taken from the method’s position in the methods and properties list of ClassWizard.

In addition, the following line is added to the dispatch map (in the .CPP file of the control class) to map the CircleOffset property to the control’s two handler functions:

DISP_PROPERTY_EX(CSampleCtrl,"CircleOffset",
   GetCircleOffset, SetCircleOffset, VT_I2)

Finally, the implementations of the GetCircleOffset and SetCircleOffset functions are added to the end of the control’s .CPP file. In most cases, you will modify the Get function to return the value of the property. The Set function will usually contain code that should be executed either before or after the property changes.

void CFooCtrl::SetCircleOffset(short nNewValue)
{
   // TODO: Add your property handler here
   SetModifiedFlag();
}

Note that ClassWizard automatically adds a call, to SetModifiedFlag, to the body of the Set function. Calling this function marks the control as modified. If a control has been modified, its new state will be saved when the container is saved. This function should be called whenever a property, saved as part of the control’s persistent state, changes value.

For a detailed implementation of the CircleOffset property, see Adding a Custom Get/Set Property in Tutorials.

See Also ActiveX Controls: Properties, ActiveX Controls: Methods, COleControl


ActiveX Controls: Advanced Property Implementation

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article describes topics related to implementing advanced properties in an ActiveX control:

  • Read-only and write-only properties

  • Returning error codes from a property

Read-only and Write-only Properties

ClassWizard provides a quick and easy method to implement read-only or write-only properties for the control.

To implement a read-only or write-only property

  1. Load the control project.

  2. On the View menu, click ClassWizard.

  3. Click the Automation tab.

  4. Click the control’s class from the Class name box.

  5. Click Add Property.

  6. In the External name box, type the name of your property.

  7. In the Implementation box, click Get/Set Methods.

  8. In the Type box, select the proper type for the property.

  9. If you want a read-only property, clear the Set function name specified by ClassWizard. If you want a write-only property, clear the Get function name.

  10. Click OK to close the Add Property dialog box.

  11. Click OK to confirm your choices and close ClassWizard.

When you do this, ClassWizard inserts the function SetNotSupported or GetNotSupported in the dispatch map entry in place of a normal Set or Get function.

If you want to change an existing property to be read- or write-only, you can edit the dispatch map manually and remove the unnecessary Set or Get function from the control class.

If you want a property to be conditionally read-only or write-only (for example, only when your control is operating in a particular mode), you can provide the Set or Get function, as normal, and call the SetNotSupported or GetNotSupported function where appropriate. For example:

void CSampleCtrl::SetMyProperty( short propVal )
{
    if ( m_bReadOnlyMode )   //  some control-specific state
        SetNotSupported( );
    else
        m_ipropVal = propVal;   //  set property as normal
}

This code sample calls SetNotSupported if the m_bReadOnlyMode data member is TRUE. If FALSE, then the property is set to the new value.

Returning Error Codes From a Property

To indicate that an error has occurred while attempting to get or set a property, use the COleControl::ThrowError function, which takes an SCODE (status code) as a parameter. You can use a predefined SCODE or define one of your own. For a list of predefined SCODEs and instructions for defining custom SCODEs, see Handling Errors in Your ActiveX Control in the article ActiveX controls: Advanced Topics.

Helper functions exist for the most common predefined SCODEs, such as COleControl::SetNotSupported, COleControl::GetNotSupported, and COleControl::SetNotPermitted.

Note ThrowError is meant to be used only as a means of returning an error from within a property’s Get or Set function or an automation method. These are the only times that the appropriate exception handler will be present on the stack.

For more information on reporting exceptions in other areas of the code, see COleControl::FireError and the section Handling Errors in Your ActiveX Control in the article ActiveX Controls: Advanced Topics.

See Also ActiveX Controls: Properties, ActiveX Controls: Methods, COleControl


ActiveX Controls: Accessing Ambient Properties

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article discusses how an ActiveX control can access the ambient properties of its control container.

A control can obtain information about its container by accessing the container’s ambient properties. These properties expose visual characteristics, such as the container’s background color, the current font used by the container, and operational characteristics, such as whether the container is currently in user mode or designer mode. A control can use ambient properties to tailor its appearance and behavior to the particular container in which it is embedded. However, a control should never assume that its container will support any particular ambient property. In fact, some containers may not support any ambient properties at all. In the absence of an ambient property, a control should assume a reasonable default value.

To access an ambient property, make a call to COleControl::GetAmbientProperty. This function expects the dispatch ID for the ambient property as the first parameter (the file OLECTL.H defines dispatch IDs for the standard set of ambient properties).

The parameters of the GetAmbientProperty function are the dispatch ID, a variant tag indicating the expected property type, and a pointer to memory where the value should be returned. The type of data to which this pointer refers will vary depending on the variant tag. The function returns TRUE if the container supports the property, otherwise it returns FALSE.

The following code example obtains the value of the ambient property called “UserMode.” If the property is not supported by the container, a default value of TRUE is assumed:

   BOOL bUserMode;
   if( !GetAmbientProperty( DISPID_AMBIENT_USERMODE,
      VT_BOOL, &bUserMode ) )
      bUserMode = TRUE;

For your convenience, COleControl supplies helper functions that access many of the commonly used ambient properties and return appropriate defaults when the properties are not available. These helper functions are as follows:

  • COleControl::AmbientBackColor

  • AmbientDisplayName

  • AmbientFont

Note Caller must call Release( ) on the returned font.

  • AmbientForeColor

  • AmbientLocaleID

  • AmbientScaleUnits

  • AmbientTextAlign

  • AmbientUserMode

  • AmbientUIDead

  • AmbientShowHatching

  • AmbientShowGrabHandles

If the value of an ambient property changes (through some action of the container), the OnAmbientPropertyChanged member function of the control is called. Override this member function to handle such a notification. The parameter for OnAmbientPropertyChanged is the dispatch ID of the affected ambient property. The value of this dispatch ID may be DISPID_UNKNOWN, which indicates that one or more ambient properties has changed, but information about which properties were affected is unavailable.


ActiveX Controls: Property Pages

Home | Overview | How Do I | FAQ | Tutorial | Sample

Property pages allow an ActiveX control user to view and change ActiveX control properties. These properties are accessed by invoking a control properties dialog box, which contains one or more property pages that provide a customized, graphical interface for viewing and editing the control properties.

ActiveX control property pages are displayed in two ways:

  • When the control’s Properties verb (OLEIVERB_PROPERTIES) is invoked, the control opens a modal property dialog box that contains the control’s property pages.

  • The container can display its own modeless dialog box that shows the property pages of the selected control.

The properties dialog box (illustrated in the figure below) consists of an area for displaying the current property page, tabs for switching between property pages, and a collection of buttons that perform common tasks such as closing the property page dialog, canceling any changes made, or immediately applying any changes to the ActiveX control.

A Properties Dialog Box

This article covers topics related to using property pages in an ActiveX control. These include:

  • Implementing the default property page for an ActiveX control

  • Adding controls to a property page

  • Adding a Help button to a property page

  • Customizing the DoDataExchange function

For more information on using property pages in an ActiveX control, see the following articles:

  • ActiveX Controls: Adding Another Custom Property Page

  • ActiveX Controls: Using Stock Property Pages

For information on using property sheets in an MFC application other than an ActiveX control, see the article Property Sheets: Overview.

Implementing the Default Property Page

If you use ControlWizard to create your control project, ControlWizard provides a default property page class for the control derived from COlePropertyPage. Initially, this property page is blank, but you can add any dialog box control or set of controls to it. Because ControlWizard creates only one property page class by default, additional property page classes (also derived from COlePropertyPage) must be created using ClassWizard. For more information on this procedure, see ActiveX Controls: Adding Another Custom Property Page.

Implementing a property page (in this case, the default) is a three step process:

To implement a property page

  1. Add a COlePropertyPage-derived class to the control project. If the project was created using ControlWizard (as in this case), the default property page class already exists.

  2. Use the dialog editor to add any controls to the property page template.

  3. Customize the DoDataExchange function of the control to exchange values between the property page control and the ActiveX control.

For example purposes, the following procedures use a simple control (named “Sample”). Sample was created using ControlWizard and contains only the stock Caption property.

Adding Controls to a Property Page

To add controls to a property page

  1. With your control project open, click the ResourceView tab in the Project Workspace window.

  2. Double-click the Dialog directory icon.

  3. Open the IDD_PROPPAGE_SAMPLE dialog box.

    ControlWizard appends the name of the project to the end of the dialog ID, in this case, Sample.

  4. Click the desired control on the Control Palette and drag and drop it into the dialog box area.

    For this example, a text label control “Caption :” and an edit box control with an IDC_CAPTION identifier are sufficient.

  5. Click Save on the Toolbar to save your changes.

Now that the user interface has been modified, you need to link the edit box with the Caption property. This is done in the following section by editing the CSamplePropPage::DoDataExchange function.

Adding a Help Button to a Property Page

To enable help in your ActiveX control, call SetHelpInfo from your property page's constructor, and override the property page's OnHelp function to invoke WinHelp.

Here is an example of changing the default property page generated by ControlWizard:

CMyPropPage::CMyPropPage() :
        COlePropertyPage(IDD, IDS_MY_PPG_CAPTION)
{
        //{{AFX_DATA_INIT(CMyPropPage)
        // NOTE: ClassWizard will add member initialization here
        //    DO NOT EDIT what you see in these blocks of generated code !
        //}}AFX_DATA_INIT

        SetHelpInfo("Custom Help String goes here!!!","My.hlp",0);
}

BOOL CMyPropPage::OnHelp(LPCTSTR lpszHelpDir)
{
        AfxGetApp()->WinHelp(0,HELP_CONTENTS);
        return TRUE;
}

The sample TESTHELP demonstrates how to create an ActiveX control with tooltips and Help.

Customizing the DoDataExchange Function

Your property page DoDataExchange function allows you to link property page values with the actual values of properties in the control. To establish links, you must map the appropriate property page fields to their respective control properties.

These mappings are implemented using the property page DDP_ functions. The DDP_ functions work like the DDX_ functions used in standard MFC dialogs, with one exception. In addition to the reference to a member variable, DDP_ functions take the name of the control property. The following is a typical entry in the DoDataExchange function for a property page.

DDP_Text(pDX, IDC_CAPTION, m_caption, _T("Caption"));

This function associates the property page’s m_caption member variable with the Caption property of the control.

Once you have the property page control inserted, you need to establish a link between the property page control, IDC_CAPTION, and the actual control property, Caption.

For more information on this procedure, see Linking Controls with Properties in Tutorials.

DDP functions are available for other dialog control types, such as check boxes, radio buttons, and list boxes. The table below lists the entire set of property page DDP_ functions and their purposes:

Property Page Functions

Function Name | Use this function to link ...
DDP_CBIndex | The selected string’s index in a combo box with a control property.
DDP_CBString | The selected string in a combo box with a control property. The selected string can begin with the same letters as the property’s value but need not match it fully.
DDP_CBStringExact | The selected string in a combo box with a control property. The selected string and the property’s string value must match exactly.
DDP_Check | A check box with a control property.
DDP_LBIndex | The selected string’s index in a list box with a control property.
DDP_LBString | The selected string in a list box with a control property. The selected string can begin with the same letters as the property’s value but need not match it fully.
DDP_LBStringExact | The selected string in a list box with a control property. The selected string and the property’s string value must match exactly.
DDP_Radio | A radio button with a control property.
DDP_Text | Text with a control property.

See Also COlePropertyPage


ActiveX Controls: Adding Another Custom Property Page

Home | Overview | How Do I | FAQ | Tutorial | Sample

Occasionally, an ActiveX control will have more properties than can reasonably fit on one property page. In this case, you can add property pages to the ActiveX control to display these properties.

This article discusses adding new property pages to an ActiveX control that already has at least one property page. For more information on adding stock property pages (font, picture, or color), see the article ActiveX Controls: Using Stock Property Pages.

The following procedures use a sample ActiveX control framework created by ControlWizard. Therefore, the class names and identifiers are unique to this example.

For more information on using property pages in an ActiveX control, see the following articles:

  • ActiveX Controls: Property Pages

  • ActiveX Controls: Using Stock Property Pages

Note It is strongly recommended that new property pages adhere to the size standard for ActiveX control property pages. The stock picture and color property pages measure 250x62 dialog units (DLUs). The standard font property page is 250x110 DLUs. The default property page created by ControlWizard uses the 250x62 DLU standard.

To create another property page

  1. With your control project open, click the ResourceView tab in the Project Workspace window.

  2. On the Insert menu, click Resource.

  3. Double-click on the dialog resource type to create a new dialog resource.

  4. Delete the OK and Cancel button controls.

  5. Right-click on the dialog template to open the Dialog Properties box, and type a resource ID.

    This example uses IDD_PROPPAGE_NEWPAGE.

  6. Click the Styles tab. From the Style box, select Child. From the Border box, select None.

    Make sure that on the Styles tab the Titlebar option is not checked, and on the More Styles tab the Visible option is not checked.

  7. Click Save on the toolbar.

  8. Double-click the dialog template to open ClassWizard.

  9. In the Adding a Class dialog box, click OK.

  10. In the Class Name box in the New Class dialog box, type a name for the new dialog class.

    (In this example, CAddtlPropPage.)

  11. If you want to change file names, click Change. Type in the names for your implementation and header files, or accept the default names.

  12. In the Base Class box, select COlePropertyPage.

  13. In the Dialog ID box, select IDD_PROPPAGE_NEWPAGE.

  14. Click OK to create the class.

  15. Click OK to close ClassWizard.

To allow the control’s users access to this new property page, make the following changes to the control’s property page IDs macro section (located in the control implementation file):

BEGIN_PROPPAGEIDS(CSampleCtrl, 2)
    PROPPAGEID(CMyPropPage::guid)
   PROPPAGEID(CAddtlPropPage::guid)
...
END_PROPPAGEIDS(CSampleCtrl)

Note that you must increase the second parameter of the BEGIN_PROPPAGEIDS macro (the property page count) from 1 to 2.

You must also modify the control implementation file (.CPP) file to include the header (.H) file of the new property page class.

The next step involves creating two new string resources that will provide a type name and a caption for the new property page.

To add new string resources to a property page

  1. With your control project open, click the ResourceView tab in the Project Workspace window.

  2. Double-click the String Table folder, then double-click the existing string table resource to which you want to add a string.

    This opens the string table in a window.

  3. Select the blank line at the end of the string table and type the text, or caption, of the string: for example, “Additional Property Page.”

    This opens a String Properties page showing Caption and ID boxes. The Caption box contains the string you typed.

  4. In the ID box, select or type an ID for the string. Press Enter when you finish.

    For example purposes, we’ve used IDS_SAMPLE_ADDPAGE for the type name of the new property page.

  5. Repeat steps 3 and 4 using IDS_SAMPLE_ADDPPG_CAPTION for the ID and “Additional Property Page” for the caption.

  6. In the .CPP file of your new property page class (in this example, CAddtlPropPage) modify the CAddtlPropPage::CAddtlPropPageFactory::UpdateRegistry so that IDS_SAMPLE_ADDPAGE is passed by AfxOleRegisterPropertyPageClass, as in the following example:
    BOOL CAddtlPropPage::CAddtlPropPageFactory::UpdateRegistry(BOOL bRegister)
{
    if (bRegister)
        return AfxOleRegisterPropertyPageClass(AfxGetInstanceHandle(),
                     m_clsid, IDS_SAMPLE_ADDPAGE);
    else
        return AfxOleUnregisterClass(m_clsid, NULL);
}
  7. Modify the constructor of CAddtlPropPage so that IDS_SAMPLE_ADDPPG_CAPTION is passed to the COlePropertyPage constructor, as follows:
    CAddtlPropPage::CAddtlPropPage() :
// ****** Add your code below this line ********** //
     COlePropertyPage(IDD,  IDS_SAMPLE_ADDPPG_CAPTION)
// ****** Add your code above this line ********** //
{
    //{{AFX_DATA_INIT(CAddtlPropPage)
    // NOTE: ClassWizard will add member initialization here
    //    DO NOT EDIT what you see in these blocks of generated code !
    //}}AFX_DATA_INIT
}

After you have made the necessary modifications rebuild your project and use Test Container to test the new property page. For more information on testing an ActiveX control with Test Container, see Test Container.


ActiveX Controls: Using Stock Property Pages

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article discusses the stock property pages available for ActiveX controls and how to use them.

For more information on using property pages in an ActiveX control, see the following articles:

  • ActiveX Controls: Property Pages

  • ActiveX Controls: Adding Another Custom Property Page

MFC provides three stock property pages for use with ActiveX controls: CLSID_CColorPropPage, CLSID_CFontPropPage, and CLSID_CPicturePropPage. These pages display a user interface for stock color, font, and picture properties, respectively.

To incorporate these property pages into a control, add their IDs to the code that initializes the control’s array of property page IDs. In the following example, this code, located in the control implementation file (.CPP), initializes the array to contain all three stock property pages and the default property page (named CMyPropPage in this example):

BEGIN_PROPPAGEIDS( CSampleCtrl, 4 )
    PROPPAGEID( CMyPropPage::guid )
    PROPPAGEID( CLSID_CFontPropPage )
    PROPPAGEID( CLSID_CColorPropPage )
    PROPPAGEID( CLSID_CPicturePropPage )
END_PROPPAGEIDS(CSampleCtrl)

Note that the count of property pages, in the BEGIN_PROPPAGEIDS macro, is 4. This represents the number of property pages supported by the ActiveX control.

After these modifications have been made, rebuild your project. Your control now has property pages for the font, picture, and color properties.

Note If the control stock property pages cannot be accessed, it may be because the MFC DLL (MFCx0.DLL) has not been properly registered with the current operating system. This usually results from installing Visual C++ under an operating system different from the one currently running.

Tip If your stock property pages are not visible (see Note above), register the DLL by running RegSvr32.exe from the command line with the path name to the DLL. For example, RegSvr32 C:\Windows\System\MFCx0.dll, for Windows and RegSvr32 C:\NT\System32\MFCx0.dll, for NT.

See Also ActiveX Controls: Adding Stock Properties


ActiveX Controls: Adding Context-Sensitive Help

You can make an ActiveX Control provide context-sensitive help on the currently selected control, property, or event by modifying the .ODL file. This article gives an example of modifying the help file for GENERIC. You can also examine the sample TESTHELP, which demonstrates how to create an ActiveX control with tooltips and Help.

The help file for a control is given by the help-file attribute in the library declaration in the .ODL file. In the following code, GENERIC.HLP is the help file for the control.

   [uuid(5CE3E2E3-8D26-101B-B883-444553540000), version(1.0),
    helpstring("GENERIC ActiveX Control module"),
    helpfile("GENERIC.HLP")]
    library GENERICLib

The associated GENERIC.HPJ file lists help-context attributes for each of the help topics:

[MAP]
GENERIC                  10
GenericShape             50
FlashColor               60
ClickIn                  70
ClickOut                 80

To specify the help topic ID for help on the control, add the help-context attribute 10 to the coclass declaration in GENERIC.ODL, as follows:

   [ uuid(5CE3E2E0-8D26-101B-B883-444553540000),
    helpstring("GENERIC Control"), helpcontext(10)]
    coclass CGENERIC

To specify the help topic ID for a control property, add the help-context attribute to the property declaration in the property list. The following code adds a help-context ID of 50 and 60 for the GenericShape and FlashColor properties, respectively:

[ uuid(5CE3E2E1-8D26-101B-B883-444553540000),
  helpstring("Dispatch interface for GENERIC Control") ]
 dispinterface _DGENERIC
{
            properties:
         // NOTE - ClassWizard will maintain property information here.
         //    Use extreme caution when editing this section.
         //{{AFX_ODL_PROP(CGENERICCtrl)
            [id(3), helpcontext(50)] GenericShapeConstants
                                                          GenericShape;
            [id(1), helpcontext(60)] OLE_COLOR FlashColor;
            [id(4)] BSTR FontName;
            [id(5)] boolean FontBold;
            [id(6)] boolean FontItalic;
            [id(7)] boolean FontStrikethru;
            [id(8)] boolean FontUnderline;
            [id(9)] float FontSize;
            [id(DISPID_BACKCOLOR), bindable, requestedit]
                                                          OLE_COLOR
BackColor
;
            [id(DISPID_CAPTION), bindable, requestedit] BSTR
                                                          Caption;
            [id(DISPID_FONT), bindable] IFontDisp* Font;
            [id(DISPID_BORDERSTYLE), bindable, requestedit]

BorderStyleConstants BorderStyle;
            [id(DISPID_ENABLED), bindable, requestedit] boolean
                                                          Enabled;
            [id(2)] MousePointerConstants MousePointer;
            [id(10)] IPictureDisp* MouseIcon;
        //}}AFX_ODL_PROP

To specify the help topic ID for a control event, add the helpcontext-attribute to the event declaration in the event list. The following code adds a help-context ID of 70 and 80 for the ClickIn and ClickOut events, respectively:

[ uuid(5CE3E2E2-8D26-101B-B883-444553540000),
  helpstring("Event interface for GENERIC Control") ]
dispinterface _DGENERICEvents
{
            properties:
            //  Event interface has no properties

            methods:
            // NOTE - ClassWizard will maintain event information here.
            //    Use extreme caution when editing this section.
            //{{AFX_ODL_EVENT(CGENERICCtrl)
            [id(1), helpcontext(70)] void ClickIn(float* X, float* Y,

     BSTR* Caption);
            [id(2), helpcontext(80)] void ClickOut();
            //}}AFX_ODL_EVENT
};


ActiveX Controls: Using Fonts in an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

If your ActiveX control displays text, you can allow the control user to change the text appearance by changing a font property. Font properties are implemented as font objects and can be one of two types: stock or custom. Stock Font properties are preimplemented font properties that you can add using ClassWizard. Custom Font properties are not preimplemented and the control developer determines the property’s behavior and usage.

This article covers the following topics:

  • Using the stock Font property

  • Using custom font properties in your control

Using the Stock Font Property

Stock Font properties are preimplemented by the class COleControl. In addition, a standard Font property page is also available, allowing the user to change various attributes of the font object, such as its name, size, and style.

Access the font object through the GetFont, SetFont, and InternalGetFont functions of COleControl. The control user will access the font object via the GetFont and SetFont functions in the same manner as any other Get/Set property. When access to the font object is required from within a control, use the InternalGetFont function.

As discussed in ActiveX Controls: Properties, adding stock properties is easy with ClassWizard’s Automation page. You choose the Font property, and ClassWizard automatically inserts the stock Font entry into the control’s dispatch map.

To add the stock Font property using ClassWizard

  1. With your control project open, open ClassWizard by clicking ClassWizard on the View menu.

  2. Click the Automation tab.

  3. In the Class Name box, select your control class name.

  4. Click Add Property.

  5. In the External name box, click Font.

  6. Click OK.

  7. Click OK to confirm your choices and close ClassWizard.

ClassWizard adds the following line to the control’s dispatch map, located in the control class implementation file:

DISP_STOCKPROP_FONT()

In addition, ClassWizard adds the following line to the control .ODL file:

[id(DISPID_FONT), bindable] IFontDisp* Font;

The stock Caption property is an example of a text property that can be drawn using the stock Font property information. Adding the stock Caption property to the control uses steps similar to those used for the stock Font property.

To add the stock Caption property using ClassWizard

  1. With your control project open, open ClassWizard by clicking ClassWizard on the View menu.

  2. Click the Automation tab.

  3. Click Add Property.

  4. In the External name box, click Caption.

  5. Click OK.

  6. Click OK to confirm your choices and close ClassWizard.

ClassWizard adds the following line to the control’s dispatch map, located in the control class implementation file:

DISP_STOCKPROP_CAPTION()

Modifying the OnDraw Function

The default implementation of OnDraw uses the Windows system font for all text displayed in the control. This means that you must modify the OnDraw code by selecting the font object into the device context. To do this, call COleControl::SelectStockFont and pass the control’s device context, as shown in the following example:

void CSampleCtrl::OnDraw( CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
   CFont* pOldFont;
   TEXTMETRIC tm;
    const CString& strCaption = InternalGetText();

   pOldFont = SelectStockFont( pdc );
   pdc->FillRect(rcBounds, CBrush::FromHandle(
   (HBRUSH )GetStockObject(WHITE_BRUSH)));
   pdc->Ellipse(rcBounds);
   pdc->GetTextMetrics(&tm);
   pdc->SetTextAlign(TA_CENTER | TA_TOP);
   pdc->ExtTextOut((rcBounds.left + rcBounds.right) / 2,
   (rcBounds.top + rcBounds.bottom - tm.tmHeight) / 2,
   ETO_CLIPPED, rcBounds, strCaption, strCaption.GetLength(),
   NULL);

   pdc->SelectObject(pOldFont);
}

Once the OnDraw function has been modified to use the font object, any text within the control is displayed with characteristics from the control’s stock Font property.

Using Custom Font Properties in Your Control

In addition to the stock Font property, the ActiveX control can have custom Font properties. To add a custom font property you must:

  • Use ClassWizard to implement the custom Font property

  • Process standard font change notifications

  • Implement a new Font notification interface

Implementing a Custom Font Property

To implement a custom Font property, you use ClassWizard to add the property and then make some modifications to the code. The following sections describe how to add the custom HeadingFont property to the Sample control.

To add a custom font property

  1. With your control project open, open ClassWizard by clicking ClassWizard on the View menu.

  2. Click the Automation tab.

  3. Click Add Property.

  4. In the External name box, type a name for the property. For this example, use HeadingFont.

  5. In the Implementation box, click Get/Set Methods.

  6. In the Return Type box, select LPFONTDISP for the property’s type.

  7. Click OK.

  8. Click OK to confirm your choices and close ClassWizard.

ClassWizard will create the code to add the HeadingFont custom property to the CSampleCtrl class and the SAMPLE.ODL file. Since HeadingFont is a Get/Set property type, ClassWizard modifies the CSampleCtrl class’s dispatch map to include a DISP_PROPERTY_EX macro entry:

BEGIN_DISPATCH_MAP(CSampleCtrl, COleControl)
//{{AFX_DISPATCH_MAP(CSampleCtrl)
DISP_PROPERTY_EX(CSampleCtrl, "HeadingFont", GetHeadingFont,
   SetHeadingFont, VT_DISPATCH)
//}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()

The DISP_PROPERTY_EX macro associates the HeadingFont property name with its corresponding CSampleCtrl class Get and Set methods, GetHeadingFont and SetHeadingFont. The type of the property value is also specified; in this case, VT_DISPATCH.

ClassWizard also adds a declaration in the control header file (.H) for the GetHeadingFont and SetHeadingFont functions and adds their function templates in the control implementation file (.CPP):

LPDISPATCH CSampleCtrl::GetHeadingFont()
{
 // TODO: Add your property handler here
 return NULL;
}

void CSampleCtrl::SetHeadingFont(LPDISPATCH newValue)
{
 // TODO: Add your property handler here
 SetModifiedFlag();
}

Finally, ClassWizard modifies the control .ODL file by adding an entry for the HeadingFont property:

[id(1)] IDispatch* HeadingFont;

Modifications to the Control Code

Now that you have added the HeadingFont property to the control, you must make some changes to the control header and implementation files to fully support the new property.

In the control header file (.H), add the following declaration of a protected member variable:

protected:

CFontHolder m_fontHeading;

In the control implementation file (.CPP), do the following:

  • Initialize m_fontHeading in the control constructor.
    CSampleCtrl::CSampleCtrl( ) : m_fontHeading( &m_xFontNotification )
{
    // [...body of constructor...]
}
  • Declare a static FONTDESC structure containing default attributes of the font.
    static const FONTDESC _fontdescHeading =
  { sizeof(FONTDESC), OLESTR("MS Sans Serif"), FONTSIZE( 12 ), FW_BOLD,
     ANSI_CHARSET, FALSE, FALSE, FALSE };
  • In the control DoPropExchange member function, add a call to the PX_Font function. This provides initialization and persistence for your custom Font property.
    void CSampleCtrl::DoPropExchange(CPropExchange* pPX)
{
    COleControl::DoPropExchange(pPX);

    // [...other PX_ function calls...]
    PX_Font(pPX, _T("HeadingFont"), m_fontHeading, &_fontdescHeading);
}
  • Finish implementing the control GetHeadingFont member function.
    LPFONTDISP CSampleCtrl::GetHeadingFont( )
{
    return m_fontHeading.GetFontDispatch( );
}
  • Finish implementing the control SetHeadingFont member function.
    void CSampleControl::SetHeadingFont( LPFONTDISP newValue )
{
    m_fontHeading.InitializeFont( &_fontdescHeading, newValue);
    OnFontChanged();    //notify any changes
    SetModifiedFlag( );
}
  • Modify the control OnDraw member function to define a variable to hold the previously selected font.
    CFont* pOldHeadingFont;
  • Modify the control OnDraw member function to select the custom font into the device context by adding the following line wherever the font is to be used.
    pOldHeadingFont = SelectFontObject(pdc, m_fontHeading);
  • Modify the control OnDraw member function to select the previous font back into the device context by adding the following line after the font has been used.
    pdc->SelectObject(pOldHeadingFont);

After the custom Font property has been implemented, the standard Font property page should be implemented, allowing control users to change the control’s current font. To add the property page ID for the standard Font property page, insert the following line after the BEGIN_PROPPAGEIDS macro:

PROPPAGEID(CLSID_CFontPropPage)

You must also increment the count parameter of your BEGIN_PROPPAGEIDS macro by one. The following line illustrates this:

BEGIN_PROPPAGEIDS(CSampleCtrl, 2)

After these changes have been made, rebuild the entire project to incorporate the additional functionality.

Processing Font Notifications

In most cases the control needs to know when the characteristics of the font object have been modified. Each font object is capable of providing notifications when it changes by calling a member function of the IFontNotification interface, implemented by COleControl.

If the control uses the stock Font property, its notifications are handled by the OnFontChanged member function of COleControl. When you add custom font properties, you can have them use the same implementation. In the example in the previous section, this was accomplished by passing &m_xFontNotification when initializing the m_fontHeading member variable.

Implementing Multiple Font Object Interfaces

The solid lines in the figure above show that both font objects are using the same implementation of IFontNotification. This could cause problems if you wanted to distinguish which font changed.

One way to distinguish between the control’s font object notifications is to create a separate implementation of the IFontNotification interface for each font object in the control. This technique allows you to optimize your drawing code by updating only the string, or strings, that use the recently modified font. The following sections demonstrate the steps necessary to implement separate notification interfaces for a second Font property. The second font property is assumed to be the HeadingFont property that was added in the previous section.

Implementing a New Font Notification Interface

To distinguish between the notifications of two or more fonts, a new notification interface must be implemented for each font used in the control. The following sections describe how to implement a new font notification interface by modifying the control header and implementation files.

Additions to the Header File

In the control header file (.H), add the following lines to the class declaration:

protected:
BEGIN_INTERFACE_PART(HeadingFontNotify, IPropertyNotifySink)
INIT_INTERFACE_PART(CSampleCtrl, HeadingFontNotify)
        STDMETHOD(OnRequestEdit)(DISPID);
        STDMETHOD(OnChanged)(DISPID);
    END_INTERFACE_PART(HeadingFontNotify)

This creates an implementation of the IPropertyNotifySink interface called HeadingFontNotify. This new interface contains a method called OnChanged.

Additions to the Implementation File

In the code that initializes the heading font (in the control constructor), change &m_xFontNotification to &m_xHeadingFontNotify. Then add the following code:

STDMETHODIMP_(ULONG) CSampleCtrl::XHeadingFontNotify::AddRef( )
{
    METHOD_MANAGE_STATE(CSampleCtrl, HeadingFontNotify)
    return 1;
}
STDMETHODIMP_(ULONG) CSampleCtrl::XHeadingFontNotify::Release( )
{
    METHOD_MANAGE_STATE(CSampleCtrl, HeadingFontNotify)
    return 0;
}

STDMETHODIMP CSampleCtrl::XHeadingFontNotify::QueryInterface( REFIID iid, LPVOID FAR* ppvObj )
{
    METHOD_MANAGE_STATE( CSampleCtrl, HeadingFontNotify )
    if( IsEqualIID( iid, IID_IUnknown ) ||
        IsEqualIID( iid, IID_IPropertyNotifySink))
    {
     *ppvObj= this;
     AddRef( );
     return NOERROR;
    }
    return ResultFromScode(E_NOINTERFACE);
}

STDMETHODIMP CSampleCtrl::XHeadingFontNotify::OnChanged(DISPID)
{
    METHOD_MANAGE_STATE( CSampleCtrl, HeadingFontNotify )
    pThis->InvalidateControl( );
    return NOERROR;
}

STDMETHODIMP CSampleCtrl::XHeadingFontNotify::OnRequestEdit(DISPID)
{
    return NOERROR;
}

The AddRef and Release methods in the IPropertyNotifySink interface keep track of the reference count for the ActiveX control object. When the control obtains access to interface pointer, the control calls AddRef to increment the reference count. When the control is finished with the pointer, it calls Release, in much the same way that GlobalFree might be called to free a global memory block. When the reference count for this interface goes to zero, the interface implementation can be freed. In this example, the QueryInterface function returns a pointer to a IPropertyNotifySink interface on a particular object. This function allows an ActiveX control to query an object to determine what interfaces it supports.

After these changes have been made to your project, rebuild the project and use Test Container to test the interface.

See Also ActiveX Controls: Using Pictures in an ActiveX Control, ActiveX Controls: Using Stock Property Pages


ActiveX Controls: Using Pictures in an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article describes the common Picture type and how to implement it in your ActiveX control. Topics include:

  • Overview of custom Picture properties

  • Implementing a custom Picture property in your ActiveX Control

Overview of Custom Picture Properties

A Picture type is one of a group of types common to all ActiveX controls. The Picture type handles metafiles, bitmaps, or icons and allows the user to specify a picture to be displayed in an ActiveX control. Custom Picture properties are implemented using a picture object and Get/Set functions that allow the control user access to the Picture property. Control users access the custom Picture property using the stock Picture property page.

In addition to the standard Picture type, Font and Color types are also available. For more information on using the standard Font type in your ActiveX control, see the article ActiveX Controls: Using Fonts in an ActiveX Control.

The ActiveX control classes provide several components you can use to implement the Picture property within the control. These components include:

  • The CPictureHolder class.

    This class provides easy access to the picture object and functionality for the item displayed by the custom Picture property.

  • Support for properties of type LPPICTUREDISP, implemented with Get/Set functions.

    Using ClassWizard you can quickly add a custom property, or properties, that supports the Picture type. For more information on adding ActiveX control properties with ClassWizard, see the article ActiveX Controls: Properties.

  • A property page that manipulates a control’s Picture property or properties.

    This property page is part of a group of stock property pages available to ActiveX controls. For more information on ActiveX control property pages, see the article ActiveX Controls: Using Stock Property Pages

Implementing a Custom Picture Property in Your ActiveX Control

When you have completed the steps outlined in this section, the control can display pictures chosen by its user. The user can change the displayed picture using a property page that shows the current picture and has a Browse button that allows the user to the select different pictures.

A custom Picture property is implemented using a process similar to that used for implementing other properties, the main difference being that the custom property must support a Picture type. Because the item of the Picture property must be drawn by the ActiveX control, a number of additions and modifications must be made to the property before it can be fully implemented.

To implement a custom Picture property, you must do the following:

  • Add code to your control project.

    A standard Picture property page ID, a data member of type CPictureHolder, and a custom property of type LPPICTUREDISP with a Get/Set implementation must be added.

  • Modify several functions in your control class.

    These modifications will be made to several functions that are responsible for the drawing of your ActiveX control.

Additions to Your Control Project

To add the property page ID for the standard Picture property page, insert the following line after the BEGIN_PROPPAGEIDS macro in the control implementation file (.CPP):

PROPPAGEID(CLSID_CPicturePropPage)

You must also increment the count parameter of your BEGIN_PROPPAGEIDS macro by one. The following line illustrates this:

BEGIN_PROPPAGEIDS(CSampleCtrl, 2)

To add the CPictureHolder data member to the control class, insert the following line under the protected section of the control class declaration in the control header file (.H):

CPictureHolder    m_pic;

It is not necessary to name your data member m_pic; any name will suffice.

Next, add a custom property that supports a Picture type:

To add a custom picture property using ClassWizard

  1. With your control project open, open ClassWizard by clicking ClassWizard on the View menu.

  2. Click the Automation tab.

  3. Click Add Property.

  4. In the External name box, type the property name. For example purposes, ControlPicture is used in this procedure.

  5. In the Implementation box, click Get/Set Methods.

  6. In the Return Type box, select LPPICTUREDISP for the property type.

  7. Type unique names for your Get and Set Functions or accept the default names. (In this example, the default names GetControlPicture and SetControlPicture are used.)

  8. Click OK to close the Add Property dialog box.

  9. Click OK to confirm your choices and close ClassWizard.

ClassWizard adds the following code between the dispatch map comments in the control header (.H) file:

afx_msg LPPICTUREDISP GetControlPicture();
afx_msg void SetControlPicture(LPPICTUREDISP newValue);

In addition, the following code was inserted in the dispatch map of the control implementation (.CPP) file:

DISP_PROPERTY_EX(CSampleCtrl, "ControlPicture", GetControlPicture, SetControlPicture, VT_PICTURE)

ClassWizard also adds the following two stub functions in the control implementation file:

LPPICTUREDISP CSampleCtrl::GetControlPicture()
{
    // TODO: Add your property handler here

    return NULL;
}

void CSampleCtrl::SetControlPicture(LPPICTUREDISP newValue)
{
    // TODO: Add your property handler here

    SetModifiedFlag();
}

Note Your control class and function names might differ from the example above.

Modifications to Your Control Project

Once you have made the necessary additions to your control project, you need to modify several functions that affect the rendering of your ActiveX control. These functions, OnResetState, OnDraw, and the Get/Set functions of a custom Picture property, are located in the control implementation file. (Note that in this example the control class is called CSampleCtrl, the CPictureHolder data member is called m_pic, and the custom picture property name is ControlPicture.)

In the control OnResetState function, add the following optional line after the call to COleControl::OnResetState:

m_pic.CreateEmpty();

This sets the control’s picture to a blank picture.

To draw the picture properly, make a call to CPictureHolder::Render in the control OnDraw function. Modify your function to resemble the following example:

void CSampleCtrl::OnDraw(
    CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
// ****** Add your code below this line ********** //
   m_pic.Render(pdc, rcBounds, rcBounds);
}

In the Get function of the control’s custom picture property, add the following line:

return m_pic.GetPictureDispatch();

In the Set function of the control’s custom Picture property, add the following lines:

m_pic.SetPictureDispatch(newValue);
InvalidateControl();

The picture property must be made persistent so that information added at design time will show up at run time. Add the following line to the COleControl-derived class's DoPropExchange function:

PX_Picture(pPX, "ControlPicture",m_pic);

Note Your class and function names might differ from the example above.

After you complete the modifications, rebuild your project to incorporate the new functionality of the custom Picture property and use Test Container to test the new property.

See Also ActiveX Controls: Using Fonts in an ActiveX Control, ActiveX Controls: Property Pages


ActiveX Controls: Advanced Topics

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article covers advanced topics related to developing ActiveX controls. These include:

  • Using database classes in ActiveX Controls

  • Implementing a parameterized property

  • Handling errors in your ActiveX Control

  • Handling special keys in the control

  • Accessing dialog controls that are invisible at run time

Using Database Classes in ActiveX Controls

Because the ActiveX control classes are part of the class library, you can apply the same procedures and rules for using database classes in a standard MFC application to developing ActiveX controls that use the MFC database classes.

For a general overview of the MFC database classes, see Databases: Overview. The article introduces both the MFC ODBC classes and the MFC DAO classes and directs you to more details on either.

Implementing a Parameterized Property

A parameterized property (sometimes called a property array) is a method for exposing a homogeneous collection of values as a single property of the control. For example, you can use a parameterized property to expose an array or a dictionary as a property. In Visual Basic, such a property is accessed using array notation:

x = obj.ArrayProp(2, 3)    ' gets element of 2D array
obj.ArrayProp(2, 3) = 7    ' sets element of 2D array

Use the OLE Automation tab of ClassWizard to implement a parameterized property. ClassWizard implements the property by adding a pair of Get/Set functions that allow the control user to access the property using the above notation or in the standard fashion.

Similar to methods and properties, parameterized properties also have a limit to the number of parameters allowed. In the case of parameterized properties, the limit is 15 parameters (with one parameter reserved for storing the property value).

The following procedure adds a parameterized property, called Array, which can be accessed as a two-dimensional array of integers.

To add a parameterized property using ClassWizard

  1. With your control project open, click ClassWizard on the View menu.

  2. Click the Automation tab.

  3. Click Add Property.

  4. In the External name box, type Array.

  5. On the Implementation menu, click Get/Set Methods.

  6. In the Type box, select short for the property’s type.

  7. In the Get Function and Set Function boxes, type unique names for your Get and Set Functions or accept the default names.

  8. Using the Parameter List grid control, add a parameter, called row (type short).

  9. Using the Parameter List grid control, add a second parameter, called column (type short).

  10. Click OK to confirm your choices.

  11. Click OK to close ClassWizard.

Changes Made by ClassWizard

When you add a custom property, ClassWizard makes changes to the control class header (.H) and the implementation (.CPP) files.

The following lines are added to the control class .H file:

afx_msg short GetArray(short row, short column);
afx_msg void SetArray(short row, short column, short nNewValue);

This code declares two functions called GetArray and SetArray that allow the user to request a specific row and column when accessing the property.

In addition, ClassWizard adds the following lines to the control dispatch map, located in the control class implementation (.CPP) file:

DISP_PROPERTY_PARAM(CSampleCtrl, "Array", GetArray, SetArray, VT_I2,
       VTS_I2 VTS_I2)

Finally, the implementations of the GetArray and SetArray functions are added to the end of the .CPP file. In most cases, you will modify the SGet function to return the value of the property. The Set function will usually contain code that should execute, either before or after the property changes.

For this property to be useful, you could declare a two-dimensional array member variable in the control class, of type short, to store values for the parameterized property. You could then modify the Get function to return the value stored at the proper row and column, as indicated by the parameters, and modify the Set function to update the value referenced by the row and column parameters.

Handling Errors in Your ActiveX Control

If error conditions occur in the control, you may need to report the error to the control container. There are two methods for reporting errors, depending on the situation in which the error occurs. If the error occurs within a property’s Get or Set function, or within the implementation of an OLE Automation method, the control should call COleControl::ThrowError, which signals the control user that an error has occurred. If the error occurs at any other time, the control should call COleControl::FireError, which fires a stock Error event.

To indicate the kind of error that has occurred, the control must pass an error code to ThrowError or FireError. An error code is an OLE status code, which has a 32-bit value. When possible, choose an error code from the standard set of codes defined in the OLECTL.H header file. The following table summarizes these codes.

ActiveX Control Error Codes

Error | Description
CTL_E_ILLEGALFUNCTIONCALL | Illegal function call
CTL_E_OVERFLOW | Overflow
CTL_E_OUTOFMEMORY | Out of memory
CTL_E_DIVISIONBYZERO | Division by zero
CTL_E_OUTOFSTRINGSPACE | Out of string space
CTL_E_OUTOFSTACKSPACE | Out of stack space
CTL_E_BADFILENAMEORNUMBER | Bad file name or number
CTL_E_FILENOTFOUND | File not found
CTL_E_BADFILEMODE | Bad file mode
CTL_E_FILEALREADYOPEN | File already open
CTL_E_DEVICEIOERROR | Device I/O error
CTL_E_FILEALREADYEXISTS | File already exists
CTL_E_BADRECORDLENGTH | Bad record length
CTL_E_DISKFULL | Disk full
CTL_E_BADRECORDNUMBER | Bad record number
CTL_E_BADFILENAME | Bad file name
CTL_E_TOOMANYFILES | Too many files
CTL_E_DEVICEUNAVAILABLE | Device unavailable
CTL_E_PERMISSIONDENIED | Permission denied
CTL_E_DISKNOTREADY | Disk not ready
CTL_E_PATHFILEACCESSERROR | Path/file access error
CTL_E_PATHNOTFOUND | Path not found
CTL_E_INVALIDPATTERNSTRING | Invalid pattern string
CTL_E_INVALIDUSEOFNULL | Invalid use of NULL
CTL_E_INVALIDFILEFORMAT | Invalid file format
CTL_E_INVALIDPROPERTYVALUE | Invalid property value
CTL_E_INVALIDPROPERTYARRAYINDEX | Invalid property array index
CTL_E_SETNOTSUPPORTEDATRUNTIME | Set not supported at run time
CTL_E_SETNOTSUPPORTED | Set not supported (read-only property)
CTL_E_NEEDPROPERTYARRAYINDEX | Need property array index
CTL_E_SETNOTPERMITTED | Set not permitted
CTL_E_GETNOTSUPPORTEDATRUNTIME | Get not supported at run time
CTL_E_GETNOTSUPPORTED | Get not supported (write-only property)
CTL_E_PROPERTYNOTFOUND | Property not found
CTL_E_INVALIDCLIPBOARDFORMAT | Invalid clipboard format
CTL_E_INVALIDPICTURE | Invalid picture
CTL_E_PRINTERERROR | Printer error
CTL_E_CANTSAVEFILETOTEMP | Can't save file to TEMP
CTL_E_SEARCHTEXTNOTFOUND | Search text not found
CTL_E_REPLACEMENTSTOOLONG | Replacements too long

If necessary, use the CUSTOM_CTL_SCODE macro to define a custom error code for a condition that is not covered by one of the standard codes. The parameter for this macro should be an integer between 1000 and 32767, inclusive. For example:

#define MYCTL_E_SPECIALERROR CUSTOM_CTL_SCODE(1000)

If you are creating an ActiveX control to replace an existing VBX control, define your ActiveX control error codes with the same numeric values the VBX control uses to ensure that the error codes are compatible.

Handling Special Keys in Your Control

In some cases you may want to handle certain keystroke combinations in a special way; for example, insert a new line when the ENTER key is pressed in a multiline text box control or move between a group of edit controls when a directional key ID pressed.

If the base class of your ActiveX control is COleControl, you can override CWnd::PreTranslateMessage to handle messages before the container receives them. When using this technique, always return TRUE if you handle the message in your override of PreTranslateMessage.

The following code example demonstrates a possible way of handling any messages related to the directional keys.

BOOL CSampleControl::PreTranslateMessage(LPMSG lpmsg)
{
    BOOL bHandleNow = FALSE;

    switch (lpmsg->message)
    {
    case WM_KEYDOWN:
        switch (lpmsg->wParam)
        {
        case VK_UP:
        case VK_DOWN:
        case VK_LEFT:
        case VK_RIGHT:
            bHandleNow = TRUE;
            break;
        }
        if (bHandleNow)
            OnKeyDown(lpmsg->wParam, LOWORD(lpmsg
                ->lParam), HIWORD(lpmsg->lParam));
        break;
    }
    return bHandleNow;
}

For more information on handling keyboard interfaces for an ActiveX control, see the ActiveX SDK documentation.

Accessing Dialog Controls That Are Invisible at Run Time

You can create dialog controls that have no user interface and are invisible at run time. If you add an invisible-at-run-time ActiveX control to a dialog box and use CWnd::GetDlgItem to access the control, the control will not work correctly. Instead, you should use one of the following techniques to obtain an object that represents the control:

  • On the Member Variables page of ClassWizard, select the control's ID, and click Add Variable. Enter a member variable name, select "Control" as the Category, and select the control's wrapper class as the Variable type.

    – or –

  • Declare a local variable and subclass as the dialog item. Insert code that resembles the following (CMyCtrl is the wrapper class, IDC_MYCTRL1 is the control's ID):
    CMyCtrl myCtrl;
myCtrl.SubclassDlgItem(IDC_MYCTRL1, this);
// ... use myCtrl ...
myCtrl.UnsubclassWindow();


ActiveX Controls: Distributing ActiveX Controls

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article discusses several issues related to redistributing ActiveX controls:

  • ANSI or Unicode control versions

  • Installing the control and its components

  • Registering the ActiveX Control

  • List of redistributable files

ANSI or Unicode Control Versions

You must decide whether to ship an ANSI or Unicode version of the control, or both. This decision is based on portability factors inherent in ANSI and Unicode character sets.

ANSI controls, which work on all Win32 operating systems, allow for maximum portability between the various Win32 operating systems. Unicode controls work on only Windows NT (version 3.51 or later), but not on Windows 95. If portability is your primary concern, ship ANSI controls. If your controls will run only on Windows NT, you can ship Unicode controls. You could also choose to ship both and have your application install the version most appropriate for the user’s operating system.

Installing ActiveX Controls and Redistributable DLLs

The setup program you provide with your ActiveX controls should create a special subdirectory of the Windows directory and install the controls’ .OCX files in it.

Tip Use the Windows GetWindowsDirectory API in your setup program to obtain the name of the Windows directory.

You may want to derive the subdirectory name from the name of your company or product.

The setup program must install the necessary redistributable DLL files in the Windows system directory. If any of the DLLs are already present on the user's machine, the setup program should compare their versions with the versions you are installing. Reinstall a file only if its version number is higher than the file already installed.

Because ActiveX controls can be used only in OLE container applications, there is no need to distribute the full set of OLE DLLs with your controls. You can assume that the containing application (or the operating system itself) has the standard OLE DLLs installed.

Registering Controls

Before a control can be used, appropriate entries must be created for it in the Windows registration database. Some ActiveX control containers provide a menu item for users to register new controls, but this feature may not be available in all containers. Therefore, you may want your setup program to register the controls when they are installed. Visual C++ includes a redistributable program, RegSvr32.exe, which can be used to register controls. Just pass the complete path and filename of the control .OCX file as an argument to RegSvr32. The MFC ActiveX controls sample REGSVR provides the source code for RegSvr32.EXE. This sample illustrates one method for performing the registration task and can be used as a guide to writing your own registration routine.

If you prefer, you can write your setup program to register the control directly instead.

Use the LoadLibrary Windows API to load the control DLL. Next, use GetProcAddress to obtain the address of the “DllRegisterServer” function. Finally, call the DllRegisterServer function. The following code sample demonstrates one possible method, where hLib stores the handle of the control library, and lpDllEntryPoint stores the address of the “DllRegisterServer” function.

HINSTANCE hLib = LoadLibrary(pszDllName);

if (hLib < (HINSTANCE)HINSTANCE_ERROR)
{
 DisplayMessage(IDS_LOADLIBFAILED, pszDllName); //unable to load DLL
 iReturn = FAIL_LOAD;                   //unable to load DLL
}

// Find the entry point.
(FARPROC&)lpDllEntryPoint = GetProcAddress(hLib,
   _T(“DllRegisterServer”));
if (lpDllEntryPoint != NULL)
 (*lpDllEntryPoint)();
else
   //unable to locate entry point

The advantage of registering the control directly is that you don’t need to invoke and load a separate process (namely, REGSVR32), reducing installation time. In addition, because registration is an internal process, the setup program can handle errors and unforeseen situations better than an external process can.

Note Before your setup program installs an ActiveX control, it should call OleInitialize. When your setup program is finished, call OleUnitialize. This ensures that the OLE system DLLs are in the proper state for registering an ActiveX control.

When you install and register a control, you should also register OLEPRO32.DLL if you are using Microsoft Windows 95 (or OLEAUT32.DLL if you are using Microsoft Windows NT 4.0 or later). Use the same procedure for registering this DLL as you did for your .OCX file. Perform this registration step only if you need to install OLEPRO32.DLL or OLEAUT32.DLL. If the DLL is installed already, you should assume that it has been registered.

If your control uses one of the stock property pages, you should also register MFCx0.DLL. Unlike OLEPRO32.DLL or OLEAUT32.DLL, you should always register this DLL, even if it is already installed.

List of Redistributable Files

This section lists the files you may redistribute with your ActiveX control. The conditions under which you may or may not redistribute these files are described in the License Agreement included in the product. Visual C++ Setup may install some of these files on your development machine, depending on the options you chose during Setup. When you redistribute any of these files, copy them from the Visual C++ CD to your distribution medium. This ensures that you are redistributing the correct version of the files. The following table lists files that must be redistributed with your ActiveX control.

Redistributable Files

File | Description
MFCx0.DLL | MFC DLL (ANSI)
MFCx0U.DLL | MFC DLL (Unicode)
MSVCRTx0.DLL | C run-time libraries
OLEPRO32.DLL (or OLEAUT32.DLL) | OLE property frame and standard types support. With Microsoft Windows NT 4.0 and later, this file is replaced by OLEAUT32.DLL.
REGSVR32.EXE | Control registration utility


ActiveX Controls: Licensing an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

Licensing support, an optional feature of ActiveX controls, allows you to control who is able to use or distribute the control. (For additional discussion of licensing issues, see Licensing Issues in Internet First Steps: Upgrading an Existing ActiveX Control.)

This article discusses the following topics:

  • Overview of ActiveX control licensing

  • Creating a licensed control

  • Licensing support

  • Customizing the licensing of an ActiveX control

ActiveX controls that implement licensing allow you, as the control developer, to determine how other people will use the ActiveX control. You provide the control purchaser with the control and .LIC file, with the agreement that the purchaser may distribute the control, but not the .LIC file, with an application that uses the control. This prevents users of that application from writing new applications that use the control, without first licensing the control from you.

Overview of ActiveX Control Licensing

To provide licensing support for ActiveX controls, the COleObjectFactory class provides an implementation for several functions in the IClassFactory2 interface: IClassFactory2::RequestLicKey, IClassFactory2::GetLicInfo, and IClassFactory2::CreateInstanceLic. When the container application developer makes a request to create an instance of the control, a call to GetLicInfo is made to verify that the control .LIC file is present. If the control is licensed, an instance of the control can be created and placed in the container. After the developer has finished constructing the container application, another function call, this time to RequestLicKey, is made. This function returns a license key (a simple character string) to the container application. The returned key is then embedded in the application.

The figure below demonstrates the license verification of an ActiveX control that will be used during the development of a container application. As mentioned previously, the container application developer must have the proper .LIC file installed on the development machine to create an instance of the control.

Verification of a Licensed ActiveX Control During Development

The next process, shown in the figure below, occurs when the end-user runs the container application.

When the application is started, an instance of the control usually needs to be created. The container accomplishes this by making a call to CreateInstanceLic, passing the embedded license key as a parameter. A string comparison is then made between the embedded license key and the control’s own copy of the license key. If the match is successful, an instance of the control is created and the application continues to execute normally. Note that the .LIC file need not be present on the control user’s machine.

Verification of a Licensed ActiveX Control During Execution

Control licensing consists of two basic components: (1) specific code in the control implementation DLL and (2) the license file. The code is composed of two (or possibly three) function calls and a character string, hereafter referred to as a “license string”, containing a copyright notice. These calls and the license string are found in the control implementation (.CPP) file. The license file, generated by ControlWizard, is a text file with a copyright statement. It is named using the project name with an .LIC extension, for example SAMPLE.LIC. A licensed control must be accompanied by the license file if design-time use is needed.

Creating a Licensed Control

When you use ControlWizard to create the control framework, it is easy to include licensing support. When the Enforce License option is selected, ControlWizard adds code to the control class to support licensing. The code consists of functions that use a key and license file for license verification. These functions also can be modified to customize the control licensing. For more information on license customization, see Customizing the Licensing of an ActiveX Control later in this article.

To add support for licensing with ControlWizard when you create your control project

  1. On the File menu, click New.

  2. In the New dialog box, click the Projects tab.

  3. Click MFC ActiveX ControlWizard.

  4. In the Project Name box, enter a project name. In the Location box, specify the project’s directory. Select either Create New Workspace or Add to Current Workspace (if you select this option, also specify the project of which this subproject will be a dependent). In the Platforms box, select a platform.

    A directory for the new project is added to the currently specified workspace directory structure. ControlWizard uses the name that you specify in the Project Name box to derive default names for most of the files and classes it creates for the control project.

  5. Click OK to continue the wizard.

  6. On the first ControlWizard page, Step 1, specify any options you want. To specify licensing support, select the Yes, please option under the question Would you like the controls in this project to have a runtime license?

  7. On the remaining ControlWizard pages, select any other options for your project.

  8. Click Finish to confirm your project choices.

    The New Project Information dialog box appears.

  9. Click OK to have ControlWizard generate the ActiveX control framework.

ControlWizard now generates an ActiveX control framework that includes basic licensing support. For a detailed explanation of the licensing code, see the next topic, Licensing Support.

Licensing Support

When you use ControlWizard to add licensing support to an ActiveX control, ControlWizard adds code that declares and implements the licensing capability is added to the control header and implementation files. This code is composed of a VerifyUserLicense member function and a GetLicenseKey member function, which override the default implementations found in COleObjectFactory . These functions retrieve and verify the control license.

Note A third member function, VerifyLicenseKey is not generated by ControlWizard, but can be overridden to customize the license key verification behavior.

These member functions are:

  • VerifyUserLicense

    Verifies that the control allows design-time usage by checking the system for the presence of the control license file. This function is called by the framework as part of processing IClassFactory2::GetLicInfo and IClassFactory::CreateInstanceLic.

  • GetLicenseKey

    Requests a unique key from the control DLL. This key is embedded in the container application and used later, in conjunction with VerifyLicenseKey, to create an instance of the control. This function is called by the framework as part of processing IClassFactory2::RequestLicKey.

  • VerifyLicenseKey

    Verifies that the embedded key and the control’s unique key are the same. This allows the container to create an instance of the control for its use. This function is called by the framework as part of processing IClassFactory2::CreateInstanceLic and can be overridden to provide customized verification of the license key. The default implementation performs a string comparison. For more information, see Customizing the Licensing of an ActiveX Control, later in this article.

Header File Modifications

ControlWizard places the following code in the control header file. In this example, two member functions of CSampleCtrl’s object factory are declared, one that verifies the presence of the control .LIC file and another that retrieves the license key to be used in the application containing the control:

BEGIN_OLEFACTORY(CSampleCtrl)        // Class factory and guid
    virtual BOOL VerifyUserLicense();
    virtual BOOL GetLicenseKey(DWORD, BSTR FAR*);
END_OLEFACTORY(CSampleCtrl)

Implementation File Modifications

ControlWizard places the following two statements in the control implementation file to declare the license filename and license string:

static const TCHAR BASED_CODE _szLicFileName[] =
   _T("License.lic");

static const WCHAR BASED_CODE _szLicString[] =
   L"Copyright (c) 1995 ";

Note If you modify szLicString in any way, you must also modify the first line in the control .LIC file or licensing will not function properly.

ControlWizard places the following code in the control implementation file to define the control class’ VerifyUserLicense and GetLicenseKey functions:

/////////////////////////////////////////////////////////////////////////////
// CLicenseCtrl::CLicenseCtrlFactory::VerifyUserLicense
// Checks for existence of a user license

BOOL CLicenseCtrl::CLicenseCtrlFactory::VerifyUserLicense()
{
   return AfxVerifyLicFile(AfxGetInstanceHandle(),
_szLicFileName, _szLicString);
}

/////////////////////////////////////////////////////////////////////////////
// CLicenseCtrl::CLicenseCtrlFactory::GetLicenseKey -
// Returns a runtime licensing key

BOOL CLicenseCtrl::CLicenseCtrlFactory::GetLicenseKey(DWORD dwReserved,
   BSTR FAR* pbstrKey)
{
   if (pbstrKey == NULL)
      return FALSE;

   *pbstrKey = SysAllocString(_szLicString);
   return (*pbstrKey != NULL);
}

Finally, ControlWizard modifies the control project .ODL file. The licensed keyword is added to the class information section of the control, as in the following example:

[ uuid(A728C248-BD2C-11CE-88F9-00AA00339DC7),
version(1.0),  helpstring("Sample OLE Custom Control
module"), control ]
library SAMPLELib

Customizing the Licensing of an ActiveX Control

Because VerifyUserLicense, GetLicenseKey, and VerifyLicenseKey are declared as virtual member functions of the control factory class, you can customize the control’s licensing behavior.

For example, you can provide several levels of licensing for the control by overriding the VerifyUserLicense and/or VerifyLicenseKey member functions. Inside this function you could adjust which properties and/or methods are exposed to the user according to the license level you detected.

You can also add code to the VerifyLicenseKey function that provides a customized method for informing the user that control creation has failed. For instance, in your VerifyLicenseKey member function you could display a message box stating that the control failed to initialize and why.

Note Another way to customize ActiveX control license verification is to check the registration database for a specific registry key, instead of calling AfxVerifyLicFile. For an example of the default implementation, see the Implementation File Modifications section of this article.

For additional discussion of licensing issues, see Licensing Issues in Internet First Steps: Upgrading an Existing ActiveX Control.

See Also Create a Program with the MFC ActiveX ControlWizard


ActiveX Controls: Localizing an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article discusses procedures for localizing ActiveX control interfaces.

If you want to adapt an ActiveX control to an international market, you may want to localize the control. Windows supports several languages in addition to the default English, including German, French, and Swedish. This can present problems for the control if its interface is in English only.

In general, ActiveX controls should always base their locale on the ambient LocaleID property. There are three ways to do this:

  • Load resources, always on demand, based on the current value of the ambient LocaleID property. The MFC ActiveX controls sample LOCALIZE, listed under CONTROLS, uses this strategy.

  • Load resources when the first control is instanced, based on the ambient LocaleID property, and use these resources for all other instances. This article demonstrates this strategy.

    Note This will not work correctly in some cases, if future instances have different locales.

  • Use the OnAmbientChanged notification function to dynamically load the proper resources for the container’s locale.

    Note This will work for the control, but the run-time DLL will not dynamically update its own resources when the ambient LocaleID property changes. In addition, run-time DLLs for ActiveX controls use the thread locale to determine the locale for its resources.

The rest of this article describes two localizing strategies. The first strategy localizes the control’s programmability interface (names of properties, methods, and events). The second strategy localizes the control’s user interface, using the container’s ambient LocaleID property. For a demonstration of control localization, see the MFC ActiveX controls sample LOCALIZE, listed under CONTROLS.

Localizing the Control’s Programmability Interface

When localizing the control’s programmability interface (the interface used by programmers writing applications that use your control), you must create a modified version of the control .ODL file (a script for building the control type library) for each language you intend to support. This is the only place you need to localize the control property names.

When you develop a localized control, include the locale ID as an attribute at the type library level. For example, if you want to provide a type library with French localized property names, make a copy of your SAMPLE.ODL file, and call it SAMPLEFR.ODL. Add a locale ID attribute to the file (the locale ID for French is 0x040c), similar to the following:

[ uuid(xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx), version(1.0), lcid(0x040c) ]
library Sample
{

Change the property names in SAMPLEFR.ODL to their French equivalents, and then use MKTYPLIB.EXE to produce the French type library, SAMPLEFR.TLB.

To create multiple localized type libraries you can add any localized .ODL files to the project and they will be built automatically.

To add an .ODL file to your ActiveX control project

  1. With your control project open, on the Project menu, click Add to Project and then Files.

    The Insert Files Into Project dialog box appears.

  2. If necessary, select the drive and directory to view.

  3. In the Files of Type box, select Interface Definition Files (*.odl,*.idl).

  4. In the file list box, double-click the .ODL file you want to insert into the project.

  5. Close the Insert Files Into Project dialog box when you have added all necessary .ODL files.

Because the files have been added to the project, they will be built when the rest of the project is built. The localized type libraries are located in the current ActiveX control project directory.

Within your code, the internal property names (usually in English) are always used and are never localized. This includes the control dispatch map, the property exchange functions, and your property page data exchange code.

Only one type library (.TLB) file may be bound into the resources of the control implementation (.OCX) file. This is usually the version with the standardized (typically, English) names. To ship a localized version of your control you need to ship the .OCX (which has already been bound to the default .TLB version) and the .TLB for the appropriate locale. This means that only the .OCX is needed for English versions, since the correct .TLB has already been bound to it. For other locales, the localized type library also must be shipped with the .OCX.

To ensure that clients of your control can find the localized type library, register your locale-specific .TLB file(s) under the TypeLib section of the Windows system registry. The third parameter (normally optional) of the AfxOleRegisterTypeLib function is provided for this purpose. The following example registers a French type library for an ActiveX control:

STDAPI DllRegisterServer(void)
{
    AFX_MANAGE_STATE(_afxModuleAddrThis);

    if (!AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid))
        return ResultFromScode(SELFREG_E_TYPELIB);
    AfxOleRegisterTypeLib(AfxGetInstanceHandle(), _tlid,
        _T("samplefr.tlb"))
    if (!COleObjectFactoryEx::UpdateRegistryAll(TRUE))
        return ResultFromScode(SELFREG_E_CLASS);

    return NOERROR;
}

When your control is registered, the AfxOleRegisterTypeLib function automatically looks for the specified .TLB file in the same directory as the control and registers it in the Windows registration database. If the .TLB file isn’t found, the function has no effect.

Localizing the Control’s User Interface

To localize a control’s user interface, place all of the control’s user-visible resources (such as property pages and error messages) into language-specific resource DLLs. You then can use the container’s ambient LocaleID property to select the appropriate DLL for the user’s locale.

The following code example demonstrates one approach to locate and load the resource DLL for a specific locale. This member function, called GetLocalizedResourceHandle for this example, can be a member function of your ActiveX control class:

HINSTANCE CSampleCtrl::GetLocalizedResourceHandle(LCID lcid)
{
    LPCTSTR lpszResDll;
    HINSTANCE hResHandle = NULL;
    LANGID lang = LANGIDFROMLCID(lcid);
    switch (PRIMARYLANGID(lang))
    {
    case LANG_ENGLISH:
        lpszResDll = “myctlen.dll”;
        break;

    case LANG_FRENCH:
        lpszResDll = “myctlfr.dll”;
        break;

    case LANG_GERMAN:
        lpszResDll = “myctlde.dll”;
        break;

    case 0:
    default:
        lpszResDll = NULL;
    }

    if (lpszResDll != NULL)
        hResHandle = LoadLibrary(lpszResDll);
    #ifndef _WIN32
        if(hResHandle <= HINSTANCE_ERROR)
           hResHandle = NULL;
    #endif

    return hResHandle;
}

Note that the sublanguage ID could be checked in each case of the switch statement, to provide more specialized localization (for example, local dialects of German). For a demonstration of this function, see the GetResourceHandle function in the MFC ActiveX controls sample LOCALIZE, listed under CONTROLS.

When the control first loads itself into a container, it can call COleControl::AmbientLocaleID to retrieve the locale ID. The control can then pass the returned locale ID value to the GetLocalizedResourceHandle function, which loads the proper resource library. The control should pass the resulting handle, if any, to AfxSetResourceHandle:

m_hResDll = GetLocalizedResourceHandle( AmbientLocaleID() );
if (m_hResDll != NULL)
    AfxSetResourceHandle(m_hResDll);

Place the code sample above into a member function of the control, such as an override of COleControl::OnSetClientSite. In addition, m_hResDLL should be a member variable of the control class.

You can use similar logic for localizing a control’s property page. To localize the property page, add code similar to the following sample to your property page’s implementation file (in an override of COlePropertyPage::OnSetPageSite):

LPPROPERTYPAGESITE pSite;
LCID lcid = 0;
if((pSite = GetPageSite()) != NULL)
    pSite->GetLocaleID(&lcid);
HINSTANCE hResource = GetLocalizedResourceHandle(lcid);
HINSTANCE hResourceSave = NULL;

if (hResource != NULL)
{
    hResourceSave = AfxGetResourceHandle();
    AfxSetResourceHandle(hResource);
}

//  Load dialog template and caption string.
COlePropertyPage::OnSetPageSite( );

if (hResource != NULL)
    AfxSetResourceHandle(hResourceSave);


ActiveX Controls: Serializing

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article discusses how to serialize an ActiveX control. Serialization is the process of reading from or writing to a persistent storage medium, such as a disk file. The Microsoft Foundation Class Library (MFC) provides built-in support for serialization in class CObject. COleControl extends this support to ActiveX controls through the use of a property exchange mechanism.

Serialization for ActiveX controls is implemented by overriding COleControl::DoPropExchange. This function, called during the loading and saving of the control object, stores all properties implemented with a member variable or a member variable with change notification.

The following topics cover the main issues related to serializing an ActiveX control:

  • Implementing DoPropExchange to serialize your control object

  • Customizing the serialization process

  • Implementing version support

Implementing the DoPropExchange Function

When you use ControlWizard to generate the control project, several default handler functions are automatically added to the control class, including the default implementation of COleControl::DoPropExchange. The following example shows the code added to classes created with ControlWizard:

void CSampleCtrl::DoPropExchange( CPropExchange* pPX)
{
   ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
   COleControl::DoPropExchange(pPX);

   // TODO: Call PX_ functions for each persistent custom property.
}

If you want to make a property persistent, modify DoPropExchange by adding a call to the property exchange function. The following example demonstrates the serialization of a custom boolean CircleShape property:

void CSampleCtrl::DoPropExchange(CPropExchange* pPX)
{
   ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
   COleControl::DoPropExchange(pPX);

   PX_Bool(pPX, "CircleShape", m_bCircleShape, TRUE);
}

The following table lists the possible property exchange functions you can use to serialize the control’s properties:

Property Exchange Functions | Purpose
PX_Blob( ) | Serializes a type Binary Large Object (BLOB) data property.
PX_Bool( ) | Serializes a type Boolean property.
PX_Color( ) | Serializes a type color property.
PX_Currency( ) | Serializes a type CY (currency) property.
PX_Double( ) | Serializes a type double property.
PX_Font( ) | Serializes a Font type property.
PX_Float( ) | Serializes a type float property.
PX_IUnknown( ) | Serializes a property of type LPUNKNOWN.
PX_Long( ) | Serializes a type long property.
PX_Picture( ) | Serializes a type Picture property.
PX_Short( ) | Serializes a type short property.
PX_String( ) | Serializes a type CString property.
PX_ULong( ) | Serializes a type ULONG property.
PX_UShort( ) | Serializes a type USHORT property.

For more information on these property exchange functions, see Persistence of OLE (ActiveX) Controls in the Class Library Reference.

Customizing the Default Behavior of DoPropExchange

The default implementation of DoPropertyExchange (as shown in the previous topic) makes a call to base class COleControl. This serializes the set of properties automatically supported by COleControl, which uses more storage space than serializing only the custom properties of the control. Removing this call allows your object to serialize only those properties you consider important. Any stock property states the control has implemented will not be serialized when saving or loading the control object unless you explicitly add PX_ calls for them.

Implementing Version Support

Version support enables a revised ActiveX control to add new persistent properties, and still be able to detect and load the persistent state created by an earlier version of the control. To make a control’s version available as part of the its persistent data, call COleControl::ExchangeVersion in the control’s DoPropExchange function. This call is automatically inserted if the ActiveX control was created using ControlWizard. It can be removed if version support is not desired. However, the cost in control size is very small (4 bytes) for the added flexibility that version support provides.

If the control was not created with ControlWizard, add a call to COleControl::ExchangeVersion by inserting the following line at the beginning of your DoPropExchange function (before the call to COleControl::DoPropExchange):

void CSampleCtrl::DoPropExchange(CPropExchange* pPX)
{
 ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
 COleControl::DoPropExchange(pPX);
...
}

You can use any DWORD as the version number. Projects generated by ControlWizard use _wVerMinor and _wVerMajor as the default. These are global constants defined in the implementation file of the project’s ActiveX control class. Within the remainder of your DoPropExchange function, you can call CPropExchange::GetVersion at any time to retrieve the version you are saving or retrieving.

In the following example, version 1 of this sample control has only a “ReleaseDate” property. Version 2 adds an “OriginalDate” property. If the control is instructed to load the persistent state from the old version, it initializes the member variable for the new property to a default value.

void CSampleCtrl::DoPropExchange(CPropExchange* pPX)
{
    ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
    COleControl::DoPropExchange(pPX);
    PX_Long(pPX, "ReleaseDate", m_releaseDate);
    if (pPX->GetVersion() >= MAKELONG(0, 2))
    {
        PX_Long(pPX, "OriginalDate", m_originalDate);
    }
    else
    {
        if (pPX->IsLoading())
            m_originalDate = 0;
    }
}

By default, a control “converts” old data to the latest format. For example, if version 2 of a control loads data that was saved by version 1, it will write the version 2 format when it is saved again. If you want the control to save data in the format last read, pass FALSE as a third parameter when calling ExchangeVersion. This third parameter is optional and is TRUE by default.


ActiveX Controls: Subclassing a Windows Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article describes the process for subclassing a common Windows control to create an ActiveX control. Subclassing an existing Windows control is a quick way to develop an ActiveX control. The new control will have the abilities of the subclassed Windows control, such as painting and responding to mouse clicks. The MFC ActiveX controls sample BUTTON, listed under CONTROLS, is an example of subclassing a Windows control.

To subclass a Windows control, complete the following tasks:

  • Override the IsSubclassedControl and PreCreateWindow member functions of COleControl

  • Modify the OnDraw member function

  • Handle any ActiveX control messages (OCM) reflected to the control

Note Much of this work is done for you by ControlWizard if you select the Subclass Windows Control option in the Control Options dialog box.

Overriding IsSubclassedControl and PreCreateWindow

To override PreCreateWindow and IsSubclassedControl, add the following lines of code to the protected section of the control class declaration:

BOOL PreCreateWindow( CREATESTRUCT& cs );
BOOL IsSubclassedControl( );

In the control implementation file (.CPP), add the following lines of code to implement the two overridden functions:

BOOL CSampleCtrl::PreCreateWindow( CREATESTRUCT& cs )
{
    cs.lpszClass = _T("BUTTON");
    return COleControl::PreCreateWindow(cs);
}
BOOL CSampleCtrl::IsSubclassedControl( )
{
    return TRUE;
}

Notice that, in this example, the Windows button control is specified in PreCreateWindow. However, any of the standard Windows controls can be subclassed. For more information on standard Windows controls, see Controls: Overview.

When subclassing a Windows control, you may want to specify particular window style (WS_) or extended window style (WS_EX_) flags to be used in creating the control's window. You can set values for these parameters in the PreCreateWindow member function by modifying the cs.style and the cs.dwExStyle structure fields. Modifications to these fields should be made using an OR operation, to preserve the default flags that are set by class COleControl. For example, if the control is subclassing the BUTTON control and you want the control to appear as a check box, insert the following line of code into the implementation of CSampleCtrl::PreCreateWindow, before the return statement:

cs.style |= BS_CHECKBOX;

This operation adds the BS_CHECKBOX style flag, while leaving the default style flag (WS_CHILD) of class COleControl intact.

Modifying the OnDraw Member Function

If you want your subclassed control to keep the same appearance as the corresponding Windows control, the OnDraw member function for the control should contain only a call to the DoSuperclassPaint member function, as in the following example:

    void CSampleCtrl::OnDraw( CDC* pdc, const CRect& rcBounds,
        const CRect& rcInvalid )
    {
     DoSuperclassPaint( pdc, rcBounds );
    }

The DoSuperclassPaint member function, implemented by COleControl, uses the window procedure of the Windows control to draw the control in the specified device context, within the bounding rectangle. This makes the control visible even when it is not active.

Note The DoSuperclassPaint member function will work only with those control types that allow a device context to be passed as the wParam of a WM_PAINT message. This includes some of the standard Windows controls, such as SCROLLBAR and BUTTON, and all of the Windows 95 common controls. For controls that do not support this behavior, you will have to provide your own code to properly display an inactive control.

Handling Reflected Window Messages

Windows controls typically send certain window messages to their parent window. Some of these messages, such as WM_COMMAND, provide notification of an action by the user. Others, such as WM_CTLCOLOR, are used to obtain information from the parent window. An ActiveX control usually communicates with the parent window by other means. Notifications are communicated by firing events (sending event notifications), and information about the control container is obtained by accessing the container’s ambient properties. Because these communication techniques exist, ActiveX control containers are not expected to process any window messages sent by the control.

To prevent the container from receiving the window messages sent by a subclassed Windows control, COleControl creates an extra window to serve as the control's parent. This extra window, called a “reflector”, is created only for an ActiveX control that subclasses a Windows control and has the same size and position as the control window. The reflector window intercepts certain window messages and sends them back to the control. The control, in its window procedure, can then process these reflected messages by taking actions appropriate for an ActiveX control (for example, firing an event).

The following table shows the messages that are intercepted and the corresponding messages that the reflector window sends.

Reflected Windows Messages

Message sent by control | Message reflected to control
WM_COMMAND | OCM_COMMAND
WM_CTLCOLOR | OCM_CTLCOLOR
WM_DRAWITEM | OCM_DRAWITEM
WM_MEASUREITEM | OCM_MEASUREITEM
WM_DELETEITEM | OCM_DELETEITEM
WM_VKEYTOITEM | OCM_VKEYTOITEM
WM_CHARTOITEM | OCM_CHARTOITEM
WM_COMPAREITEM | OCM_COMPAREITEM
WM_HSCROLL | OCM_HSCROLL
WM_VSCROLL | OCM_VSCROLL
WM_NOTIFY | OCM_NOTIFY
WM_PARENTNOTIFY | OCM_PARENTNOTIFY

Note If the control runs on a Win32 system, there are several types of WM_CTLCOLOR messages it may receive instead of WM_CTLCOLOR. For more information, see WM_CTLCOLORBTN, WM_CTLCOLORDLG, WM_CTLCOLOREDIT, WM_CTLCOLORLISTBOX, WM_CTLCOLORMSGBOX, WM_CTLCOLORSCROLLBAR, WM_CTLCOLORSTATIC.

An ActiveX control container may be designed to perform message reflection itself, eliminating the need for COleControl to create the reflector window and reducing the run-time overhead for a subclassed Windows control. COleControl detects whether the container supports this capability by checking for a MessageReflect ambient property with a value of TRUE.

To handle a reflected window message, add an entry to the control message map and implement a handler function. Because reflected messages are not part of the standard set of messages defined by Windows, ClassWizard does not support adding such message handlers. However, it is not difficult to add a handler manually.

To add a message handler for a reflected window message manually do the following:

  • In the control class .H file, declare a handler function. The function should have a return type of LRESULT and two parameters, with types WPARAM and LPARAM, respectively. For example:
    class CSampleCtrl : public COleControl
{
 protected:
LRESULT OnOcmCommand( WPARAM wParam, LPARAM lParam );
...
}
  • In the control class .CPP file, add an ON_MESSAGE entry to the message map. The parameters of this entry should be the message identifier and the name of the handler function. For example:
    BEGIN_MESSAGE_MAP(CSampleCtrl, COleControl)
//{{AFX_MSG_MAP(CSampleCtrl)
...
ON_MESSAGE(OCM_COMMAND, OnOcmCommand)
...
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
  • Also in the .CPP file, implement the OnOcmCommand member function to process the reflected message. The wParam and lParam parameters are the same as those of the original window message.

For an example of how reflected messages are processed, refer to the MFC ActiveX controls sample BUTTON, listed under CONTROLS. It demonstrates an OnOcmCommand handler that detects the BN_CLICKED notification code and responds by firing (sending) a Click event.


ActiveX Controls: Using Data Binding in an ActiveX Control

Home | Overview | How Do I | FAQ | Tutorial | Sample

One of the more powerful uses of ActiveX controls is data binding, which allows a property of the control to bind with a specific field in a database. When this control property is modified by the control user, the control notifies the database that the value has changed and requests that the record field be updated. The database then notifies the control of the success or failure of the request.

This article covers the control side of your task. Implementing the data binding interactions with the database is the responsibility of the control container. How you manage the database interactions in your container is beyond the scope of this documentation. How you prepare the control for data binding is explained in the rest of this article.

This article covers the following topics:

  • How data binding works

  • Defining a bindable property

How Data Binding Works

Data binding allows a database entry, such as a record field, to be linked to a property of an ActiveX control. This control is typically used in a form view and provides a visual interface to the current record state. The figure below shows a conceptual representation of this linkage. In this example, the ActiveX control is an edit box which has bound its Text property to the Name field of a record. When modifications are made to the control’s Text property, these changes are communicated to the database.

Conceptual Diagram of a Data Bound Control

When an ActiveX control property is bound, the developer must make sure that the control is able to send notifications to the database when the property changes. The notification is sent to an interface provided by the control container, which processes it and returns the database’s response to the control.

The COleControl class provides two member functions that make data binding an easy process to implement. The first function, BoundPropertyRequestEdit is used to request permission to change the property value. BoundPropertyChanged, the second function, is called after the property value has been successfully changed.

Defining a Bindable Property

If the control was created using ControlWizard, data binding is automatically enabled. Once you have successfully compiled your ActiveX control, you can use ClassWizard to incorporate data binding. ClassWizard allows you to choose which properties to make bindable and provides several binding options.

Binding option | Description
Sends OnRequestEdit | The property requests permission from the database before modifying the value.
Visible to the End User | The container displays the property in a property binding dialog.
Default Bindable Property | Makes the bindable property the control container’s default choice.

The following procedure demonstrates adding a text property to an existing control that subclasses an edit box. This property can then be bound to a record field. The figure below shows the Data Binding dialog box.

The Data Binding Dialog Box

To add a bound property using ClassWizard

  1. With your control project open, click ClassWizard on the View menu.

  2. Click the Automation tab.

  3. In the Class Name box, select the name of your control class.

  4. Click Add Property.

  5. In the External name box, type the external name of the property. For this example, use RecordName.

  6. In the Implementation box, click Get/Set Methods.

    Note Data binding is not supported for properties implemented as member variables.

  7. In the Type box, select the property’s type. For this example, select BSTR.

    Note Do this step after setting the Implementation option. If you try to do it before, the BSTR type is not available in the Type box.

  8. Type unique names for your Get and Set Functions or accept the default names.

  9. Click OK to confirm your choices and close the Add Property dialog box.

  10. Click Data Binding.

  11. Select the Bindable Property check box.

  12. Set any other data binding options you desire.

  13. Click OK to confirm your choices and close the Data Binding dialog box.

  14. Click OK to confirm your choices and close ClassWizard.

After completing this process you will have a property called RecordName that can be bound to a string-valued field in a database.

Code Changes Related to Data Bound Property

Implementing a bound property requires code changes in some of the control project files.

The following code is added to the control declaration file (.H) between the dispatch map comments:

   afx_msg BSTR GetRecordName( );
   afx_msg void SetRecordName( LPCTSTR lpszNewValue );

In addition, changes will be made to the control implementation file. The following sample shows what would be added if you followed the example in the procedure:

BSTR CSampleCtrl::GetRecordName()
{
   CString strResult;
   // TODO: Add your property handler here

   return strResult.AllocSysString();
}

void CSampleCtrl::SetRecordName(LPCTSTR lpszNewValue)
{
   // TODO: Add your property handler here

   SetModifiedFlag( );
}

To fully implement the control data binding you have to modify the GetRecordName and SetRecordName functions. For example, in the SetRecordName function, you would make a call to BoundPropertyRequestEdit to obtain permission to change the value of the bound property. If it was successful, you would save the new value and handle any other actions needed before notifying the container that the property has changed. This notification would be done by calling BoundPropertyChanged. The following code sample demonstrates this:

void CSampleCtrl::SetRecordName( LPCTSTR lpszNewValue )
{
 if( !BoundPropertyRequestEdit( dispidRecordName) )
    SetNotPermitted( );
//TODO: Actually set property value.
 BoundPropertyChanged( dispidRecordName);
 SetModifiedFlag( );

}


ActiveX Controls: Adding an ActiveX Control to an Existing CDK Project

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article provides step-by-step instructions for combining two existing ActiveX control projects into an existing OLE Custom Control Developer’s Kit (CDK) project. For clarity, the first control project is named Proj1; the second is named Proj2. After you have successfully completed this procedure, you will need to follow the steps detailed in the article ActiveX Controls: Converting a CDK Project to a Visual C++ Project to use this project with Visual C++ 4.0.

To protect the original code from becoming corrupted, work with the two controls in a separate directory. For example purposes, we’ve named the directory COMBINED. It is also recommended that you use the development environment for modifying and saving project files.

To successfully add an ActiveX control to an existing CDK project, you must:

  • Collect all relevant .H, .CPP, .PPG, and .RC files

  • Combine both .ODL files into one .ODL file

  • Modify the PROJ2.MAK makefile

  • Combine the resources of both controls

  • Build the resultant project

Collecting Implementation Files

The Proj1 and Proj2 directories both contain files that you can simply copy to the COMBINED directory with no changes. These files are used mainly to initialize the DLL and provide basic implementation of the control classes. Copy the following files into the COMBINED directory:

  • STDAFX.H, STDAFX.CPP

  • PROJ2.RC, RESOURCE.H

  • PROJ2CTL.BMP, PROJ2.ICO

  • PROJ1.H

  • PROJ2.H, PROJ2.CPP

  • PROJ1CTL.H, PROJ1CTL.CPP

  • PROJ1PPG.H, PROJ1PPG.CPP

  • PROJ2CTL.H, PROJ2CTL.CPP

  • PROJ2PPG.H, PROJ2PPG.CPP

  • PROJ2.DEF

Also copy two other files, used as templates, to the COMBINED directory:

  • PROJ2.MAK

    In a following section, this makefile will be modified to include the necessary files from PROJ1.

  • PROJ2.ODL

    This file will eventually contain both the Proj1 and Proj2 ActiveX control interfaces.

Merging the .ODL Files

Because there are two controls in the project, you will have to merge PROJ1.ODL into PROJ2.ODL. The .ODL file contains definitions for interfaces, so you need copy only those interfaces unique to Proj1 and insert them into the PROJ2.ODL file.

To merge PROJ1.ODL with PROJ2.ODL

  1. From the PROJ1 .ODL file, copy the lines that are in the same position as the lines indicated in the following .ODL file:
    //
//  Type Library for Proj1.DLL
//
    #include <otldisp.h>
    [ uuid(A7A91CE8-B974-101A-8077-00AA00339DC7), version(1.0),
      helpstring("PROJ1 ActiveX control module") ]
    library Proj1
    {
    importlib("stdole.tlb");
    importlib("stdtype.tlb");

// ****** Copy code below this line ********** //
        [ uuid(A7A91CE6-B974-101A-8077-00AA00339DC7),
          helpstring("Dispatch interface for PROJ1 Control") ]
        dispinterface IProj1Ctrl
        {
            properties:
                //{{AFX_ODL_PROP(CProj1Ctrl)
                //}}AFX_ODL_PROP

            methods:
            //{{AFX_ODL_METHOD(CProj1Ctrl)
            //}}AFX_ODL_METHOD

        };

        [ uuid(A7A91CE7-B974-101A-8077-00AA00339DC7),
          helpstring("Event interface for PROJ1 Control") ]
        dispinterface IProj1CtrlEvents
        {
            properties:
                //  Event interface has no properties

            methods:
                //{{AFX_ODL_EVENT(CProj1Ctrl)
            //}}AFX_ODL_EVENT
        };
// ****** Copy code above this line ********** //
//  Class information for CProj1Ctrl

     [ uuid(003256C3-AA78-11CE-8C98-00AA00339DC7),
       helpstring("Proj1 Control"), control ]
     coclass Proj1
     {
          [default] dispinterface _DProj1;
          [default, source] dispinterface
            _DProj1Events;
     };
};
  2. Paste the code that you copied in the example above into PROJ2.ODL, just prior to the last closing brace.

Modifying the Proj2 Makefile

Now that you have moved the needed files from Proj1 to the COMBINED directory, incorporate them into the Proj2 makefile.

Note If PROJ2.MAK is an external makefile, edit it directly to add the new files from Proj1.

To incorporate Proj1 files into the Proj2 makefile

  1. On the File menu, click Open.

  2. Select the drive and directory containing the project workspace that you want to open.

    For this example, select the COMBINED directory and choose the Proj2 project (Proj2.dsp).

  3. Click Open to open the project and close the Open dialog box.

  4. On the Insert menu, click File.

  5. In the Insert File dialog box, double-click PROJ1CTL.CPP.

    This inserts the file into the project.

  6. Repeat Steps 4 and 5 for PROJ1PPG.CPP.

  7. Click Close to save changes to the makefile and to close the Insert File dialog box.

Combining the Resources of Both Controls

The last modification required before building the project is to add the resources from PROJ1.RC to PROJ2.RC. This is easy to do because you can drag and drop resources from one project into another.

To add resources from Proj1 to Proj2

  1. On the File menu, click Open.

  2. Select the drive and directory containing the project workspace that you want to open.

    For this example select the COMBINED directory and choose the Proj2 project (Proj2.dsp).

  3. On the File menu, click Open.

  4. Select PROJ1.RC from the PROJ1 directory.

  5. Click OK to close the Open dialog box.

  6. Click the ResourceView tab in the Project Workspace window to see resource folders for the two projects.

  7. Click the ‘+” icons to expand the resource folders for the two projects.

  8. Double-click a folder for a particular resource type in Proj1 to open the folder.

  9. Drag and drop the bitmap, icon, string resources, and property pages from Proj1 into Proj2. Be sure to hold down the CTRL key so the resources are copied and not moved.

    For an example of a similar procedure, see Adding Help to Scribble After the Fact in Tutorials.

  10. After you have added the resources, save the changes by clicking Save.

Building the New Project

After completing the preceding steps, you can build the new project as you would any ActiveX control project. Once the project has been successfully built, register the controls. You can then use Test Container, or another container application, to test your ActiveX control. For more information on this procedure, see the article Test Container.

Please note that the .CLW file for Proj2 needs to be rebuilt to include the new classes added from the PROJ1 project.

To rebuild your .CLW file

  1. On the File menu, click Open.

  2. Select the drive and directory containing the project workspace that you want to open.

    For this example, select the COMBINED directory and choose the Proj2 project (Proj2.dsp).

  3. Click the ResourceView tab to view resources in the project.

  4. Click ClassWizard on the View menu.

    A dialog box will appear, stating that your project’s .CLW file does not exist.

  5. Click Yes to select the source files to be used.

  6. Click OK to select all files in the project and rebuild the .CLW file.

ClassWizard will now open with all classes from Proj2 loaded and accessible.


ActiveX Controls: VBX Control Migration

Home | Overview | How Do I | FAQ | Tutorial | Sample

SVBX control migration was available only through the VBX template tool, a part of the ControlWizard found in version 1.x of the CDK. Because this tool was removed from the ControlWizard shipped with Visual C++ 4.0, migrating existing VBX controls requires version 1.x of the CDK. The only option for VBX migration using VC ++ 4.0 is to create a framework from ControlWizard and manually port the entire code base of the VBX control into the ActiveX control framework.

As stated above, developers with existing VBX controls can use the VBX template tool, found in the CDK ControlWizard, to convert existing VBX controls to the ActiveX control format.

The VBX template tool helps you migrate your VBX custom control to an ActiveX control. The template tool uses model information in the .VBX file and creates a Visual C++ project file, as well as source code files for creating the ActiveX control. These files can be compiled and linked to produce a working framework for the ActiveX control.

Once this framework is built and tested, the next step is to take code from your VBX source files and place it in the appropriate areas of the generated OLE source files. The transplanted code will probably require some degree of modification to work in the new source code files.

This article explains:

  • Preparing your .VBX source code files for conversion

  • Using the VBX template tool

  • What gets converted

  • Building and testing the framework of your ActiveX control

  • Where to go from here

If you want to port your ActiveX control framework to Visual C++ 4.0, see the article ActiveX Controls: Converting a CDK Project to a Visual C++ Project.

Preparing the VBX Custom Control

For the VBX template tool to properly translate the VBX control, you must expose the VBX control model information to the template builder, using the VBGetModelInfo function. If your VBX source code does not already define this function, first define a MODELINFO structure containing a specific Visual Basic version number, and a NULL-terminated array of MODEL structures. The MFC ActiveX controls sample CIRC3, listed under CONTROLS, defines the MODELINFO structure as follows:

LPMODEL modellistCircle[] =
    {
    &modelCircle,
    NULL
    };

Note Remember to NULL-terminate the array of model pointers.

MODELINFO modelinfoCircle =
    {
    VB_VERSION,        // VB version being used
    modellistCircle    // MODEL list
    };

Note If your .VBX file provides different models to support earlier versions, you should create similar MODELINFO structures to point to those models. The CIRC3 custom control, for example, also defines ModelinfoCircle_VB1 and ModelinfoCircle_VB2 structures.

Once you have defined the MODELINFO structure(s), you can define the VBGetModelInfo function, as an export, in your source code. The MFC ActiveX controls sample CIRC3, listed under CONTROLS, defines the function:

LPMODELINFO FAR PASCAL _export VBGetModelInfo
(
    USHORT usVersion
)
{
    if (usVersion <= VB100_VERSION)
        return &modelinfoCircle_Vb1;

    if (usVersion <= VB200_VERSION)
        return &modelinfoCircle_Vb2;
    else
        return &modelinfoCircle;
}

Once this function is defined, rebuild your VBX control before using the template tool.

Running the VBX Template Tool

After your VBX control has been built with the VBGetModelInfo function, as described in the previous topic, you are ready to run the VBX template tool.

As mentioned before, you must be using the ControlWizard that shipped with version 1.x of the CDK. The template tool is not available with Visual C++ 4.0.

If you only need to use the ControlWizard shipped with version 1.x of the CDK, you can copy two files from the distribution CD. These two files, CTLWZLIB.DLL and MFCCTLWZ.EXE, is in the vc152\msvccdk directory of the Visual C++ Version 1.52 CD.

To run the VBX template tool

  1. Start ControlWizard by running MFCCTLWZ.EXE from the DOS command prompt or Windows Explorer.

  2. When the ControlWizard dialog box appears, change to the desired drive and directory and enter a project name. ControlWizard automatically creates a new subdirectory with the same name as the project.

  3. Click Control Options. When the Control Options dialog box appears, choose the Use VBX Control as Template check box.

  4. Click Select VBX Control.

  5. In the Use VBX Control as Template dialog box, type the .VBX file name, including the drive and directory path. Alternatively, you can click Browse to locate and select your .VBX file. All control names defined in the .VBX file are displayed in the control name drop-down list. Select the desired control name from the drop-down list.

    Note If you select a .VBX file that does not properly export the model information (as described in the Note in Preparing the VBX Custom Control), Visual C++ may crash at this point.

  6. Click OK twice to close the Use VBX Control as Template box and the Control Options box. Click OK from ControlWizard to prepare to create the template.

  7. When the New Control Information box appears, a summary of the generated files is displayed. Click Create to create all the files for the ActiveX control.

  8. When the VBX template tool is finished, your project directory should contain the following files (the files listed here assume the VBX example control, CIRC3.VBX, was used as the project):
    • CIRC3.CLW

    • CIRC3.CPP

    • CIRC332.DEF

    • CIRC3.DEF

    • CIRC3.H

    • CIRC3.ICO

    • CIRC3.MAK

    • CIRC332.MAK

    • MAKEFILE

    • CIRC3.ODL

    • CIRC3.RC

    • CIRC3.RC2

    • CIRC3CTL.BMP

    • CIRC3CTL.CPP

    • CIRC3CTL.H

    • CIRC3PPG.CPP

    • CIRC3PPG.H

    • README.TXT

    • RESOURCE.H

    • STDAFX.CPP

    • STDAFX.H

In addition, a subdirectory for the Type library file is created. If you are using the 16-bit version of the CDK, it is called TLB16. If you are using the 32-bit version of the CDK, it is called OBJDU.

The README.TXT file contains a summary description of each file created by the VBX template tool. These files are all that is required to build a complete working framework of the new ActiveX control.

What Gets Converted

The template generated by the VBX template tool is similar to the "blank" template that is generated when you use ControlWizard to create a new control, with the following differences:

Stock Properties and Events

ControlWizard converts most of the standard properties and events in your .VBX to fully implemented stock properties and events in the template's source code.

Stock properties supported by the VBX template tool include:

  • BorderStyle

  • Enabled

  • Font

  • Caption

  • Text

  • ForeColor

  • BackColor

  • hWnd

Stock events supported by the VBX template tool include:

  • Click

  • DblClick

  • KeyDown

  • KeyPress

  • KeyUp

  • MouseDown

  • MouseMove

  • MouseUp

Note A number of properties not mentioned above that were formerly standard in the .VBX Control model are automatically supported by ActiveX as standard "extender" properties (e.g., Left, Top, Height, Width). Therefore, these properties are not needed in an ActiveX control, and are not converted by the VBX template tool.

Currently Unimplemented Properties and Events

Stock properties of the VBX model not supported:

  • DragIcon

  • DragMode

  • MouseCursor

  • MousePointer

Stock events of the VBX model not supported:

  • DragDrop

  • DragOver

  • LinkOpen

  • LinkClose

  • LinkError

  • LinkNotify

Custom Properties and Events

Custom properties and events in your VBX control are provided in the template as stub functions. In order to make these properties and events functional, you must port the implementation code from your VBX control’s source files into the appropriate files in the new control template. These places are indicated by similar comments in the template's source code files:

    // TODO: Initialize your control's instance data here.

Building and Testing the ActiveX Control Framework

After ControlWizard generates the basic framework for your VBX control, build and test the control to familiarize yourself with ActiveX control behavior. The following sections describe this process and demonstrate how to use Test Container to test your new ActiveX control.

Creating the Type Library for the ActiveX Control

Note that the following information only applies if you are using the 16-bit version of Visual C++. If you are using the 32-bit version of Visual C++, the type library is automatically generated by the control makefile.

Before you can compile and link the control template, you must create a type library, used by control containers that use your control. This will be based on the information contained in the Object Description Library (.ODL) file created by the porting tool.

To create the type library

  1. Load the project make file that you generated by running the VBX template tool.

  2. On the Tools menu, click Make TypeLib. MKTYPLIB.EXE creates a type library based on the .ODL file in the project. After building successfully, MKTYPLIB automatically adds the resulting *.TLB file to your project. The information in this .TLB file will be built into your .DLL as a resource.

Compiling, Linking, and Registering the ActiveX Control Framework

Note that the following information only applies if you are using the 16-bit version of Visual C++.

After creating the Type Library, you can build the framework control by choosing Build from the Visual C++ Project menu.

When the project has built successfully, you must register the new control before you can test it. Choose Register Control from the Tools menu. A message box appears, indicating that the control was successfully registered.

Testing the ActiveX Control Framework

For procedures on testing your ActiveX control framework, see the article Test Container.

Where to Go From Here

When you are satisfied that the control framework is working properly, the next step is to port the implementation of your ActiveX control's custom properties and events from your VBX source code to the new control's source code files. To do this, use ClassWizard and the implementation guidelines in the ActiveX controls articles. Remember to back up your files frequently and to use Test Container to test each new block of code as you go.

Once the VBX control is ported to a CDK project, you could port the CDK project to Visual C++ 4.0 by following the steps given in the article ActiveX Controls: Converting a CDK Project to a Visual C++ Project.


ActiveX Controls: Converting a CDK Project to a Visual C++ Project

Home | Overview | How Do I | FAQ | Tutorial | Sample

This article discusses converting existing OLE Custom Control Developer's Kit (CDK) projects (versions 1.0 and 1.1) to current Visual C++ projects. Because the support for ActiveX controls has been fully integrated into MFC, there are several changes that need to be made to an existing project before the control can be built successfully.

In summary, the necessary changes are:

  • Remove all references to the OCS30 libraries.

  • Remove RESIDENTNAME from the module definition (.DEF) file.

  • Delete the contents of the project's output directories and TLB16 directory.

For demonstration purposes, this article converts a project named SAMPLE32.

To remove all references to the OCS30 libraries

  1. In Visual C++, open the control's 32-bit project file, in this case, SAMPLE32.MAK.

  2. On the Build menu, click Settings to open the Project Settings dialog box.

  3. Click the Link tab.

  4. Select the first target in the Output File Name box, in this case, Win32 ANSI Debug (SAMPLE.OCX).

  5. In the Object/Library Modules box, delete any library name of the form "OCS30*.LIB." For example, when the Win32 ANSI Debug target is selected, delete the library name "OCS30D.LIB."

  6. Repeat steps 4 and 5 for each target in the Output File Name box.

  7. Click the OK button to accept the changes and close the Object/Library Modules box.

To remove RESIDENTNAME from the module definition file

  1. In Visual C++, open the control's 32-bit module definition file, in this case, SAMPLE32.DEF.

  2. Delete each occurrence of the string RESIDENTNAME from the file. There are typically four occurrences of this string.

    For example, the following line of code:

    DllCanUnloadNow     @1 RESIDENTNAME

    should be changed to:

    DllCanUnloadNow     @1 PRIVATE

    Note that using the PRIVATE modifier avoids warnings from the linker. Similarly, symbols such as DllRegisterServer and DllUnregisterServer should also have the PRIVATE modifier.

  3. On the File menu, click Save.

The final step is to remove any existing directories and project files from earlier builds. This ensures a clean build with the new project settings.

To delete the contents of the project's output directories and the TLB16 subdirectory

  • At the DOS command prompt, File Manager, or Windows Explorer, delete the directories named “TLB16”, "OBJ32", "OBJD32", "OBJU32" and "OBJDU32" from the project directory.

ANSI/Unicode Changes

One of the changes that occurred between the original release of the CDK and its integration into VC ++ 4.0, was the removal of the MFCANS32 DLL. This DLL was responsible for the ANSI/Unicode translation layer used for Unicode-based OLE interfaces with an ANSI-targeted control. If your control supported licensing, it was affected by this change.

In order for your control to function properly, you will need to make some code changes to the control implementation (.CPP) files.

  • If your control supports licensing, change the declaration of the license string, found in the control implementation (.CPP) file, to the following:
    static const OLECHAR BASED_CODE _szLicString[] =
OLESTR("Licensed Control Copyright (c) 1994-1995 My Corporation");
  • Every direct call to the OLE API that passes a string as a parameter must first convert the string by making a call to MultiByteToWideChar, and then passing the result to the SysAllocString function. The following example uses new MFC conversion macros to simplify calling the SysAllocString function:
    USES_CONVERSION;
TCHAR szMyString[] = _T("Licensed Control Copyright (c)
   1994-1995 My Corporation"); //a multi-byte string
BSTR strWide = SysAllocString(T2OLE(szMyString));

The USES_CONVERSION macro and the T2OLE macro are described in Technical Note 59, Using MFC MBCS/Unicode Conversion Macros. These macros simplify calling functions that require conversion between Unicode and MBCS, particularly OLE API functions such as SysAllocString.

See Also Create a Program with the MFC ActiveX ControlWizard


ActiveX Control Containers

Home | Overview | How Do I | Tutorial | Sample

An ActiveX control container is a container that fully supports ActiveX controls and can incorporate them into its own windows or dialogs. An ActiveX control is a reusable software element that you can use in many development projects. Controls allow your application’s user to access databases, monitor data, and make various selections within your applications. For more information on ActiveX controls, see the article ActiveX Control Topics.

Control containers typically take two forms in a project:

  • Dialogs and dialog-like windows such as form views, where an ActiveX control is used somewhere in the dialog box.

  • Windows in an application, where an ActiveX control is used in a toolbar, or other location in the user window.

The ActiveX control container interacts with the control via exposed methods and properties. These methods and properties, which can be accessed and modified by the control container, are accessed through a wrapper class in the ActiveX control container project. The embedded ActiveX control can also interact with the container by firing (sending) events to notify the container that an action has occurred. The control container can choose to act upon these notifications or not.

Additional articles discuss several topics, from creating an ActiveX control container project to basic implementation issues related to ActiveX control containers built with Visual C++:

  • Overview: Creating an ActiveXControl Container

  • ActiveX Control Containers: Manually Enabling ActiveX Control Containment

  • ActiveX Control Containers: Inserting a Control into a Control Container Application

  • ActiveX Control Containers: Connecting an ActiveX Control to a Member Variable

  • ActiveX Control Containers: Handling Events from an ActiveX control

  • ActiveX Control Containers: Viewing and Modifying Control Properties

  • ActiveX Control Containers: Programming ActiveX Controls in an ActiveX Control Container

  • ActiveX Control Containers: Using Controls in a Non-Dialog Container

For more information about using ActiveX controls in a dialog box, see the Dialog Editor documentation in Visual C++ User’s Guide.

For a list of articles that explain the details of developing ActiveX controls using Visual C++ and the MFC ActiveX control classes, see ActiveX controls. The articles are grouped by functional categories.


ActiveX Control Containers: Manually Enabling ActiveX Control Containment

Home | Overview | How Do I | Tutorial | Sample

If you did not enable ActiveX control support when you used AppWizard to generate your application, you will have to add this support manually. This article describes the process for manually adding ActiveX control containment to an existing OLE container application. If you know in advance that you want ActiveX control support in your OLE container, see the article Overview: Creating an ActiveX Control Container. In addition, you can use the Gallery’s ActiveX control Containment component to automatically add control containment to your application.

Note This article uses a dialog-based ActiveX control container project named Container and an embedded control named Circ2 as examples in the procedures and code.

To support ActiveX controls, you must add one line of code to two of your project’s files.

  • Modify your main dialog’s InitInstance function (found in CONTAINER.CPP) by making a call to AfxEnableControlContainer, as in the following example:
    // CContainerApp initialization

BOOL CContainerApp::InitInstance()
{
AfxEnableControlContainer();
...
}
  • Add the following to your project’s STDAFX.H header file:
    #include <Afxdisp.h>

After you have completed these steps, rebuild your project by clicking Build on the Build menu.


ActiveX Control Containers: Inserting a Control into a Control Container Application

Home | Overview | How Do I | Tutorial | Sample

Before you can access an ActiveX control from an ActiveX control container application, you must use Gallery to add the ActiveX control to the container application.

To add an ActiveX control to the ActiveX control container project

  1. On the Project menu, select Add to Project and then Components and Controls.

    The Components and Controls Gallery appears. By default, you are looking into the Gallery folder.

  2. Open the Registered ActiveX controls folder.

  3. Select the control you want by clicking the ActiveX control icon in the list.

  4. Click Insert.

  5. Click OK to confirm that you want to insert the control.

    The Confirm Classes dialog box appears. This dialog box lists the class (or classes) that will be generated for each inserted control. It also lists the class name, header, and implementation files, which can be modified. (In the case of Container and Circ2, only one class is generated.)

  6. Click OK to accept the class generated by Gallery.

  7. Click Close to close the Components and Controls Gallery.

    An icon representing each control installed appears on the dialog editor Controls toolbar.

Once you complete this procedure, the class generated by Gallery, referred to as a wrapper class, is added to your project. This class is used as an interface between the control container and the embedded control.


ActiveX Control Containers: Connecting an ActiveX Control to a Member Variable

Home | Overview | How Do I | Tutorial | Sample

The easiest way to access an ActiveX control from within its control container application is to associate the ActiveX control with a member variable of the dialog class that will contain the control.

Note This is not the only way to access an embedded control from within a container class, but for the purposes of this article it is sufficient.

Adding a member variable to the dialog class

  1. Load your ActiveX container project.

  2. On the View menu, click ClassWizard.

  3. Choose the Member Variables tab.

  4. In the Class Name list box, select the main dialog class. For example, CContainerDlg.

  5. In the Control IDs list box, select the control ID of the embedded ActiveX control. For example, IDC_CIRC2CTRL1.

  6. Click Add Variable.

    The Add Member Variable dialog box appears.

  7. In the Member Variable Name box enter a name.

    For example, m_circ2ctl.

  8. In the Category box, click Control.

    The Variable Type edit box automatically contains the name of the control wrapper class.

    Note Additional entries in the Category drop-down list box are for exposed properties of the ActiveX control.

  9. Click OK to close the Add Member Variables dialog box.

  10. Click OK to accept your choices and exit ClassWizard.


ActiveX Control Containers: Handling Events from an ActiveX Control

Home | Overview | How Do I | Tutorial | Sample

This article discusses using ClassWizard to install event handlers for ActiveX controls in an ActiveX control container. The event handlers are used to receive notifications (from the control) of certain events and perform some action in response. This notification is called “firing” the event.

Note This article uses a dialog-based ActiveX control container project named Container and an embedded control named Circ2 as examples in the procedures and code.

Using the Message Maps tab in ClassWizard, you can create a map of events that can occur in your ActiveX control container application. This map, called an “event sink map,’’ is created and maintained by ClassWizard when you add event handlers to the control container class. Each event handler, implemented with an event map entry, maps a specific event to a container event handler member function. This event handler function is called when the specified event is fired by the ActiveX control object.

For more information on event sink maps, see Event Sink Maps in the Class Library Reference.

To create an event handler function

  1. On the View menu, click ClassWizard.

  2. Click the Message Maps tab.

  3. In the Class name box, select the dialog box class that contains the ActiveX control. For this example, use CContainerDlg.

  4. In the Object IDs box, select the control ID of the embedded ActiveX control. For this example, use IDC_CIRC2CTRL1.

    The Messages box displays a list of events that can be fired by the embedded ActiveX control. Any member function shown in bold already has handler functions assigned to it.

  5. Select the message you want the application to handle. For this example, select ClickIn.

  6. Click Add Function.

    A suggested name for the handler function appears in the Member Functions box. For this example, use the suggested name.

  7. Click OK to close the Add Function dialog box.

  8. Click Edit Code to jump to the event handler code in the implementation (.CPP) file of CContainerDlg or Close to close ClassWizard.

Event Handler Modifications to the Project

When you use ClassWizard to add event handlers, an event sink map is declared and defined in your project. The following statements are added to the control .CPP file the first time an event handler is added. This code declares an event sink map for the dialog box class (in this case, CContainerDlg):

BEGIN_EVENTSINK_MAP(CContainerDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CContainerDlg)
    //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

As you use ClassWizard to add events, an event map entry (ON_EVENT) is added to the event sink map and an event handler function is added to the container’s implementation (.CPP) file.

The following example declares an event handler, called OnClickInCirc2Ctrl, for the Circ2 control’s ClickIn event:

BEGIN_EVENTSINK_MAP(CContainerDlg, CDialog)
    //{{AFX_EVENTSINK_MAP(CContainerDlg)
   ON_EVENT(CContainerDlg, IDC_CIRC2CTRL1, 1 /*
ClickIn */, OnClickInCirc2ctrl, VTS_I4 VTS_I4)
   //}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()

In addition, the following template is added to the CContainerDlg class implementation (.CPP) file for the event handler member function:

BOOL CContainerDlg::OnClickInCirc2ctrl1(OLE_XPOS_PIXELS nX, OLE_YPOS_PIXELS nY)
{
   // use nX and nY here
}

For more information on event sink macros, see Event Sink Maps in the Class Library Reference.


ActiveX Control Containers: Viewing and Modifying Control Properties

Home | Overview | How Do I | Tutorial | Sample

When you insert an ActiveX control into a project, it is useful to view and change the properties supported by the ActiveX control. This article discusses how to use the Visual C++ resource editor to do this.

If your ActiveX control container application uses embedded controls, you can view and modify the control’s properties while in the resource editor. You can also use the resource editor to set property values during design time. The resource editor then automatically saves these values in the project’s resource file. Any instance of the control will then have its properties initialized to these values.

This procedure assumes that you have used Gallery to insert a control into your project. For information, see ActiveX Control Containers: Inserting a Control Into a Control Container Application.

The first step in viewing the control’s properties is to add an instance of the control to the project’s dialog template.

To add a control to the dialog template

  1. In the Project Workspace window, load your ActiveX control container project into the developer environment. For this example, use the Container project.

  2. Click ResourceView in the Project Workspace window.

  3. Open the Dialog folder.

  4. Open your main dialog box template.

  5. On the Controls toolbar, select the control icon.

  6. Click a spot within the dialog box area to insert the control.

Once you have added the control to the dialog box, double-click on the control to bring up the control Properties dialog box. Use this dialog box to modify and test new properties immediately.


ActiveX Control Containers: Programming ActiveX Controls in an ActiveX Control Container

Home | Overview | How Do I | Tutorial | Sample

This article describes the process for accessing the exposed methods and properties of embedded ActiveX controls. Basically, you will follow these steps:

  1. Insert an ActiveX control into the ActiveX container project using Gallery.

  2. Define a member variable (or other form of access) of the same type as the ActiveX control wrapper class.

  3. Program the ActiveX control using predefined member functions of the wrapper class.

For this discussion, assume you’ve created a dialog-based project (named Container) with ActiveX control support. The Circ2 sample control, Circ2, will be added to the resulting project.

Once the Circ2 control is inserted into the project (step 1), insert an instance of the Circ2 control into the application’s main dialog box.

To add the Circ2 control to the dialog template

  1. Load the ActiveX control container project. For this example, use the Container project.

  2. Click ResourceView in the Project Workspace window.

  3. Open the Dialog folder.

  4. Double-click the main dialog box template. For this example, use IDD_CONTAINER_DIALOG.

  5. Click the Circ2 control icon on the Controls toolbar.

  6. Click a spot within the dialog box to insert the Circ2 control.

  7. On the File menu, click Save All to save all modifications to the dialog box template.

Modifications to the Project

To enable the Container application to access the Circ2 control, Gallery automatically adds the wrapper class (CCirc2) implementation file (.CPP) to the Container project and the wrapper class header (.H) file to the dialog box implementation file:

//{{AFX_INCLUDES(CContainerDlg)
#include "circ2.h"
//}}AFX_INCLUDES
// ContainerDlg.cpp : implementation file
//

The Wrapper Class Header (.H) File

To get and set properties (and invoke methods) for the Circ2 control, the CCirc2 wrapper class provides a declaration of all exposed methods and properties. In the example, these declarations are found in CIRC2.H. The following sample is the portion of class CCirc2 that defines the exposed interfaces of the ActiveX control:

class CCirc2 : public CWnd
{
...
// Attributes
public:
   OLE_COLOR GetBackColor();
   void SetBackColor(OLE_COLOR);
   BOOL GetCircleShape();
   void SetCircleShape(BOOL);
   short GetCircleOffset();
   void SetCircleOffset(short);
   unsigned long GetFlashColor();
   void SetFlashColor(unsigned long);
   BSTR GetCaption();
   void SetCaption(LPCTSTR);
   LPFONTDISP GetFont();
   void SetFont(LPFONTDISP);
   OLE_COLOR GetForeColor();
   void SetForeColor(OLE_COLOR);
   CString GetNote();
   void SetNote(LPCTSTR);

// Operations
public:
   void AboutBox();
};

These functions can then be called from other of the application’s procedures using normal C++ syntax. For more information on using this member function set to access the control’s methods and properties, see the section Programming the ActiveX control.

Member Variable Modifications to the Project

Once the ActiveX control has been added to the project and embedded in a dialog box container, it can be accessed by other parts of the project. The easiest way to access the control is to create a member variable of the dialog class, CContainerDlg (step 2), that is of the same type as the wrapper class added to the project by Gallery. You can then use the member variable to access the embedded control at any time.

When ClassWizard adds the m_circ2ctl member variable to the project, it also adds the following lines to the header file (.H) of the CContainerDlg class:

class CContainerDlg : public CDialog
{
// Construction
public:
   CContainerDlg(CWnd* pParent = NULL);   // standard constructor

// Dialog Data
   //{{AFX_DATA(CContainerDlg)
   enum { IDD = IDD_CONTAINER_DIALOG };
   CCirc2   m_circ2ctl;
   //}}AFX_DATA
};

In addition, ClassWizard adds a DDX_Control call to the CContainerDlg’s implementation of DoDataExchange:

DDX_Control(pDX, IDC_CIRC2CTRL1, m_circ2ctl);

Programming the ActiveX Control

At this point, you have inserted the ActiveX control into your dialog template and created a member variable for it. You can now use common C++ syntax to access the properties and methods of the embedded control.

As noted (in The Wrapper Class Header (.H) File), the header file (.H) for the CCirc2 wrapper class, in this case CIRC2.H, contains a list of member functions that you can use to get and set any exposed property value. Member functions for exposed methods are also available.

A common place to modify the control’s properties is in the OnInitDialog member function of the main dialog class. This function is called just before the dialog box appears and is used to initialize its contents, including any of its controls.

The following code example uses the m_circ2ctl member variable to modify the Caption and CircleShape properties of the embedded Circ2 control:

BOOL CContainerDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   // Add "About..." menu item to system menu.

   // IDM_ABOUTBOX must be in the system command range.
   ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
   ASSERT(IDM_ABOUTBOX < 0xF000);

   CMenu* pSysMenu = GetSystemMenu(FALSE);
   CString strAboutMenu;
   strAboutMenu.LoadString(IDS_ABOUTBOX);
   if (!strAboutMenu.IsEmpty())
   {
      pSysMenu->AppendMenu(MF_SEPARATOR);
      pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
   }

   m_circ2ctl.SetCaption(_T("Circ 2 Control"));
   if( !m_circ2ctl.GetCircleShape())
      m_circ2ctl.SetCircleShape(TRUE);

   return TRUE;  // return TRUE  unless you set the focus to a control
}


ActiveX Control Containers: Using Controls in a Non-Dialog Container

Home | Overview | How Do I | Tutorial | Sample

In some applications, such as an SDI or MDI application, you will want to embed a control in a window of the application. The Create member function of the wrapper class, inserted by Gallery, can create an instance of the control dynamically, without the need for a dialog box.

The Create member function has the following parameters:

lpszWindowName

A pointer to the text to be displayed in the control’s Text or Caption property (if any).

dwStyle

Windows styles. For a complete list, see CWnd::CreateControl.

rect

Specifies the control’s size and position.

pParentWnd

Specifies the control’s parent window, usually a CDialog. It must not be NULL.

nID

Specifies the control ID and can be used by the container to refer to the control.

One example of using this function to dynamically create an ActiveX control would be in a form view of an SDI application. You could then create an instance of the control in the WM_CREATE handler of the application.

For this example, CMyView is the main view class, CCirc2 is the wrapper class, and CIRC2.H is the header (.H) file of the wrapper class.

Implementing this feature is a four-step process.

To dynamically create an ActiveX control in a non-dialog window

  1. Insert CIRC2.H in CMYVIEW.H, just before the CMyView class definition:
    #include "circ2.h"
  2. Add a member variable (of type CCirc2) to the protected section of the CMyView class definition located in CMYVIEW.H:
    class CMyView : public CView
{
...
protected:

CCirc2 m_myCtl;
...
};
  3. Add a WM_CREATE message handler to class CMyView.

  4. In the handler function, CMyView::OnCreate, make a call to the control’s Create function using the this pointer as the parent window:
    int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   if (MyView::OnCreate(lpCreateStruct) == -1)
      return -1;

// ****** Add your code below this line ********** //

   m_myCtl.Create(NULL, WS_VISIBLE,
      CRect(50,50,100,100), this, 0);
   m_myCtl.SetCaption(_T(“Control created”));

// ****** Add your code above this line ********** //

   return 0;
}
  5. Rebuild the project. A Circ2 control will be created dynamically whenever the application’s view is created.


Testing Properties and Events with Test Container

Home | Overview | How Do I

The Test Container allows you to test a control's functionality by changing its properties, invoking its methods, and firing its events. See Test Container for more information.


Clipboard Topics

Home | Overview | How Do I

The Clipboard is the standard Windows method of transferring data between a source and a destination. It can also be very useful in OLE operations. With the advent of OLE, there are two Clipboard mechanisms in Windows. The standard Windows Clipboard API is still available, but it has been implemented by the OLE data transfer mechanism. OLE uniform data transfer (UDT) supports Cut, Copy, and Paste with the Clipboard and drag and drop.

The Clipboard is a system service shared by the entire Windows session, so it does not have a handle or class of its own. You manage the Clipboard through member functions of class CWnd.

What do you want to know more about?

  • Using the traditional Windows Clipboard API

  • When to use which Clipboard mechanism

  • Copying and pasting data with OLE

  • Adding other Clipboard formats


Clipboard: When to Use Each Clipboard Mechanism

Home | Overview | How Do I

Follow these guidelines in using the Clipboard:

  • Use the OLE Clipboard mechanism now to enable new capabilities in the future. While the standard Clipboard API will be maintained, the OLE mechanism is the future of data transfer.

  • Use the OLE Clipboard mechanism if you are writing an OLE application or you want any of the OLE features, such as drag and drop.

  • Use the OLE Clipboard mechanism if you are providing OLE formats.

What do you want to do?

  • Use the OLE Clipboard mechanism

  • Use the Windows Clipboard mechanism


Clipboard: Using the Windows Clipboard

Home | Overview | How Do I

This article describes how to use the standard Windows Clipboard API within your MFC application.

Most applications for Windows support cutting or copying data to the Windows Clipboard and pasting data from the Clipboard. The Clipboard data formats vary among applications. The framework supports only a limited number of Clipboard formats for a limited number of classes. You will normally implement the Clipboard-related commands — Cut, Copy, and Paste — on the Edit menu for your view. The class library defines the command IDs for these commands: ID_EDIT_CUT, ID_EDIT_COPY, and ID_EDIT_PASTE. Their message-line prompts are also defined.

Messages and Commands in the Framework, explains how to handle menu commands in your application by mapping the menu command to a handler function. As long as your application does not define handler functions for the Clipboard commands on the Edit menu, they remain disabled. To write handler functions for the Cut and Copy commands, implement selection in your application. To write a handler function for the Paste command, query the Clipboard to see whether it contains data in a format your application can accept. For example, to enable the Copy command, you might write a handler something like the following:

void CMyView::OnEditCopy()
{
  if ( !OpenClipboard() )
  {
    AfxMessageBox( "Cannot open the Clipboard" );
    return;
  }
  // Remove the current Clipboard contents
  if( !EmptyClipboard() )
  {
    AfxMessageBox( "Cannot empty the Clipboard" );
    return;
  }
  // ...
  // Get the currently selected data
  // ...
  // For the appropriate data formats...
  if ( ::SetClipboardData( CF_??, hData ) == NULL )
  {
    AfxMessageBox( "Unable to set Clipboard data" );
    CloseClipboard();
    return;
  }
  // ...
  CloseClipboard();
}

The Cut, Copy, and Paste commands are only meaningful in certain contexts. The Cut and Copy commands should be enabled only when something is selected, and the Paste command only when something is in the Clipboard. You can provide this behavior by defining update handler functions that enable or disable these commands depending on the context. For more information, see How to Update User-Interface Objects.

The Microsoft Foundation Class Library does provide Clipboard support for text editing with the CEdit and CEditView classes. The OLE classes also simplify implementing Clipboard operations that involve OLE items. For more information on the OLE classes, see Clipboard: Using the OLE Clipboard Mechanism.

Implementing other Edit menu commands, such as Undo (ID_EDIT_UNDO) and Redo (ID_EDIT_REDO), is also left to you. If your application does not support these commands, you can easily delete them from your resource file using the Visual C++ resource editors.

What do you want to know more about?

  • Copying and pasting data

  • Using the OLE Clipboard mechanism


Clipboard: Using the OLE Clipboard Mechanism

Home | Overview | How Do I

OLE uses standard formats and some OLE-specific formats for transferring data through the Clipboard.

When you cut or copy data from an application, the data is stored on the Clipboard to be used later in paste operations. This data is in a variety of formats. When a user chooses to paste data from the Clipboard, the application can choose which of these formats to use. The application should be written to choose the format that provides the most information, unless the user specifically asks for a certain format, using Paste Special. Before continuing, you may want to read the Data Objects and Data Sources (OLE) family of articles. They describe the fundamentals of how data transfers work, and how to implement them in your applications.

Windows defines a number of standard formats that can be used for transferring data through the Clipboard. These include metafiles, text, bitmaps, and others. OLE defines a number of OLE-specific formats, as well. It is a good idea for applications that need more detail than given by these standard formats to register their own custom Clipboard formats. Use the Win32 API function RegisterClipboardFormat to do this.

For example, Microsoft Excel registers a custom format for spreadsheets. This format carries much more information than, for example, a bitmap does. When this data is pasted into an application that supports the spreadsheet format, all the formulas and values from the spreadsheet are retained and can be updated if necessary. Microsoft Excel also puts data on the Clipboard in formats so that it can be pasted as an OLE item. Any OLE document container can paste this information as an embedded item. This embedded item can be changed using Microsoft Excel. The Clipboard also contains a simple bitmap of the image of the selected range on the spreadsheet. This can also be pasted into OLE document containers or into bitmap editors, like Paint. In the case of a bitmap, however, there is no way to manipuate the data as a spreadsheet.

To retrieve the maximum amount of information from the Clipboard, applications should check for these custom formats before pasting data from the Clipboard.

For example, to enable the Copy command, you might write a handler something like the following:

void CMyView::OnEditCopy()
{
  // Create an OLE data source on the heap
  COleDataSource* pData = new COleDataSource;
  // ...
  // Get the currently selected data
  // ...
  // For the appropriate data formats...
  pData->CacheData( CF_??, hData );
  // ...
  // The Clipboard now owns the allocated memory
  // and will delete this data object
  // when new data is put on the Clipboard
  pData->SetClipboard();
}

What do you want to know more about?

  • Copying and pasting data

  • Adding other Clipboard formats

  • Using the Windows Clipboard

  • OLE

  • OLE data objects and data sources and uniform data transfer


Clipboard: Copying and Pasting Data

Home | Overview | How Do I

This article describes the minimum work necessary to implement copying to and pasting from the Clipboard in your OLE application. It is recommended that you read the Data Objects and Data Sources (OLE) family of articles before proceeding.

Before you can implement either copying or pasting, you must first provide functions to handle the Copy, Cut, and Paste options on the Edit menu.

Copying or Cutting Data

To copy data to the Clipboard

  1. Determine whether the data to be copied is native data or is an embedded or linked item.
    • If the data is embedded or linked, obtain a pointer to the COleClientItem object that has been selected.

    • If the data is native and the application is a server, create a new object derived from COleServerItem containing the selected data. Otherwise, create a COleDataSource object for the data.
  2. Call the selected item’s CopyToClipboard member function.

  3. If the user chose a Cut operation instead of a Copy operation, delete the selected data from your application.

To see an example of this sequence, see the OnEditCut and OnEditCopy functions in the MFC OLE sample programs OCLIENT and HIERSVR. Note that these samples maintain a pointer to the currently selected data, so step 1 is already complete.

Pasting Data

Pasting data is more complicated than copying it because you need to choose the format to use in pasting the data into your application.

To paste data from the Clipboard

  1. In your view class, implement OnEditPaste to handle users choosing the Paste option from the Edit menu.

  2. In the OnEditPaste function, create a COleDataObject object and call its AttachClipboard member function to link this object to the data on the Clipboard.

  3. Call COleDataObject::IsDataAvailable to check whether a particular format is available.

    Alternately, you can use COleDataObject::BeginEnumFormats to look for other formats until you find one most suited to your application.

  4. Perform the paste of the format.

For an example of how this works, see the implementation of the OnEditPaste member functions in the view classes defined in the MFC OLE sample programs OCLIENT and HIERSVR.

Tip The main benefit of separating the paste operation into its own function is that the same paste code can be used when data is dropped in your application during a drag-and-drop operation. As in OCLIENT and HIERSVR, your OnDrop function can also call DoPasteItem, reusing the code written to implement Paste operations.

To handle the Paste Special option on the Edit menu, see the article Dialog Boxes in OLE.

What do you want to know more about?

  • Adding other Clipboard formats

  • OLE data objects and data sources and uniform data transfer

  • OLE drag and drop

  • OLE


Clipboard: Adding Other Formats

Home | Overview | How Do I

This article explains how to expand the list of supported formats, particularly for OLE support. The article Clipboard: Copying and Pasting Data describes the minimum implementation necessary to support copying and pasting from the Clipboard. If this is all you implement, the only formats placed on the Clipboard are CF_METAFILEPICT, CF_EMBEDSOURCE, CF_OBJECTDESCRIPTOR, and possibly CF_LINKSOURCE. Most applications will need more formats on the Clipboard than these three.

Registering Custom Formats

To create your own custom formats, follow the same procedure you would use when registering any custom Clipboard format: pass the name of the format to the RegisterClipboardFormat function and use its return value as the format ID.

Placing Formats on the Clipboard

To add more formats to those placed on the Clipboard, you must override the OnGetClipboardData function in the class you derived from either COleClientItem or COleServerItem (depending on whether the data to be copied is native). In this function, you should use the following procedure.

To place formats on the Clipboard

  1. Create a COleDataSource object.

  2. Pass this data source to a function that adds your native data formats to the list of supported formats by calling COleDataSource::CacheGlobalData.

  3. Add standard formats by calling COleDataSource::CacheGlobalData for each standard format you want to support.

This technique is used in the MFC OLE sample program HIERSVR (examine the OnGetClipboardData member function of the CServerItem class). The only difference in this sample is that step three is not implemented because HIERSVR supports no other standard formats.

What do you want to know more about?

  • OLE data objects and data sources and uniform data transfer

  • OLE drag and drop

  • OLE


Control Topics

Home | Overview | Samples

Controls are objects that users can interact with to enter or manipulate data. They commonly appear in dialog boxes or on toolbars. This article family covers three main kinds of controls:

  • Windows common controls, including owner-drawn controls

  • ActiveX Controls

  • Other control classes supplied by the Microsoft Foundation Class Library (MFC)

Windows Common Controls

The Windows operating system has always provided a number of Windows common controls. These control objects are programmable, and the Visual C++ dialog editor supports adding them to your dialog boxes. The Microsoft Foundation Class Library (MFC) supplies classes that encapsulate each of these controls, as shown in the table Windows Common Controls and MFC Classes. (Some items in the table have related articles that describe them further. For controls that lack articles, see the documentation for the MFC class.)

Class CWnd is the base class of all window classes, including all of the control classes. The Windows common controls are supported in the following environments:

  • Windows 95

  • Windows NT, version 3.51 and later

  • Win32s, version 1.3 (Visual C++ version 4.2 and later do not support Win32s)

The older common controls — check boxes, combo boxes, edit boxes, list boxes, option buttons, pushbuttons, scroll bar controls, and static controls — were available in earlier versions of Windows as well.

ActiveX Controls

ActiveX controls, formerly known as OLE controls, can be used in dialog boxes in your applications for Windows, or in HTML pages on the World Wide Web. For more information, see ActiveX Control Topics.

Other MFC Control Classes

In addition to classes that encapsulate all of the Windows common controls and that support programming your own ActiveX controls (or using ActiveX controls supplied by others), MFC supplies the following control classes of its own:

  • CBitmapButton

  • CCheckListBox

  • CDragListBox

Finding Information About Windows Common Controls

The table below briefly describes each of the Windows common controls, including the control's MFC wrapper class.

Windows Common Controls and MFC Classes

Control | MFC Class | Description | New in Windows 95?
animation | CAnimateCtrl | displays successive frames of an AVI video clip | yes
button | CButton | pushbuttons that cause an action; also used for check boxes, radio buttons, and group boxes | no
combo box | CComboBox | combination of an edit box and a list box | no
date and time picker | CDateTimeCtrl | allows the user to choose a specific date or time value | yes
edit box | CEdit | boxes for entering text | no
extended combo box | CComboBoxEx | a combo box control with the ability to display images | yes
header | CHeaderCtrl | button that appears above a column of text; controls width of text displayed | yes
hotkey | CHotKeyCtrl | window that enables user to create a "hot key" to perform an action quickly | yes
image list | CImageList | collection of images used to manage large sets of icons or bitmaps (image list isn't really a control; it supports lists used by other controls) | yes
list | CListCtrl | window that displays a list of text with icons | yes
list box | CListBox | box that contains a list of strings | no
month calendar | CMonthCalCtrl | control that displays date information | yes
progress | CProgressCtrl | window that indicates progress of a long operation | yes
rebar | CRebarCtrl | tool bar that can contain additional child windows in the form of controls | yes
rich edit | CRichEditCtrl | window in which user can edit with character and paragraph formatting (see Classes Related to Rich Edit Controls) | yes
scroll bar | CScrollBar | scroll bar used as a control inside a dialog box (not on a window) | no
slider | CSliderCtrl | window containing a slider control with optional tick marks | yes
spin button | CSpinButtonCtrl | pair of arrow buttons user can click to increment or decrement a value | yes
static-text | CStatic | text for labeling other controls | no
status bar | CStatusBarCtrl | window for displaying status information, similar to MFC class CStatusBar | yes
tab | CTabCtrl | analogous to the dividers in a notebook; used in "tab dialog boxes" or property sheets | yes
toolbar | CToolBarCtrl | window with command-generating buttons, similar to MFC class CToolBar | yes
tool tip | CToolTipCtrl | small pop-up window that describes purpose of a toolbar button or other tool | yes
tree | CTreeCtrl | window that displays a hierarchical list of items | yes

What do you want to know more about?

  • An individual control: see the table Windows Common Controls and MFC Classes in this article for links to all controls

  • Making and using controls

  • Using the dialog editor to add controls

  • Adding controls to a dialog box by hand

  • Deriving control classes from the MFC control classes

  • Using common controls as child windows

  • Notifications from common controls


Making and Using Controls

Home | Overview | Sample

You make most controls for dialog boxes in the Visual C++ dialog editor. But you can also create controls in any dialog box or window.

What do you want to know more about?

  • Creating controls in a dialog box

  • Using the dialog editor to add controls

  • Adding controls by hand (without the dialog editor)

  • Deriving controls from a standard control

  • Using a common control as a child window

  • Receiving notification messages from a control

  • Using DDX and DDV to initialize controls and retrieve values from them

  • Creating a dialog class member variable with the Control property, and programming the control through this data member

  • Individual controls: see the table Windows Common Controls and MFC Classes for links to all common controls

  • Dialog boxes

  • Dialog bars


Using Common Controls in a Dialog Box

Home | Sample

The Windows common controls can be used in dialog boxes, form views, record views, and any other window based on a dialog template. The following procedure, with minor changes, will work for forms as well.

To use a common control in a dialog box

  1. Place the control on the dialog template using the dialog editor.

  2. Add to the dialog class a member variable that represents the control. In the Add Member Variable dialog box, select Control in the Category drop-down list.

  3. If this common control is providing input to the program, declare additional member variable(s) in the dialog class to handle those input values.

    Note ClassWizard will not support adding these member variables. You need to add them using the context menu in ClassView.

  4. In OnInitDialog for your dialog class, set the initial conditions for the common control. Using the member variable created in the previous step, use the member functions to set initial value and other settings. See the following descriptions of the controls for details on settings.

    You can also use dialog data exchange (DDX) to initialize controls in a dialog box.

  5. In handlers for controls on the dialog box, use the member variable to manipulate the control. See the following descriptions of the controls for details on methods.

    Note The member variable will exist only as long as the dialog box itself exists. You will not be able to query the control for input values after the dialog box has been closed. To work with input values from a common control, override OnOK in your dialog class. In your override, query the control for input values and store those values in member variables of the dialog class.

    You can also use dialog data exchange to set or retrieve values from the controls in a dialog box.

What do you want to do?

  • Add controls to a dialog box by hand instead of with the dialog editor

  • Derive my control from one of the standard Windows common controls

  • Use a common control as a child window

  • Receive notification messages from a control

  • Use dialog data exchange (DDX)

See Also Windows Common Controls and MFC Classes


Using the Dialog Editor to Add Controls

Home | Sample

When you create your dialog-template resource with the dialog editor, you drag controls from a controls palette and drop them into the dialog box. This adds the specifications for that control type to the dialog-template resource. When you construct a dialog object and call its Create or DoModal member function, the framework creates a Windows control and places it in the dialog window on screen.

You can instead create controls by hand if you want. This is more work.

See Also Windows Common Controls and MFC Classes


Adding Controls By Hand

Home | Sample

CDialog::OnInitDialog

You can either add controls to a dialog box with the dialog editor or add them yourself, with code.

To create a control object yourself, you will usually embed the C++ control object in a C++ dialog or frame-window object. Like many other objects in the framework, controls require two-stage construction. You should call the control's Create member function as part of creating the parent dialog box or frame window. For dialog boxes, this is usually done in OnInitDialog, and for frame windows, in OnCreate.

The following example shows how you might declare a CEdit object in the class declaration of a derived dialog class and then call the Create member function in OnInitDialog. Because the CEdit object is declared as an embedded object, it is automatically constructed when the dialog object is constructed, but it must still be initialized with its own Create member function.

class CMyDialog : public CDialog
{
protected:
    CEdit m_edit;   // Embedded edit object
public:
    virtual BOOL OnInitDialog();
};

The following OnInitDialog function sets up a rectangle, then calls Create to create the Windows edit control and attach it to the uninitialized CEdit object.

BOOL CMyDialog::OnInitDialog()
{
    CDialog::OnInitDialog();
    CRect rect(85, 110, 180, 210);

    m_edit.Create(WS_CHILD | WS_VISIBLE | WS_TABSTOP |
             ES_AUTOHSCROLL | WS_BORDER, rect, this, ID_EXTRA_EDIT);
    m_edit.SetFocus();
    return FALSE;
}

After creating the edit object, you can also set the input focus to the control by calling the SetFocus member function. Finally, you return 0 from OnInitDialog to show that you set the focus. If you return a nonzero value, the dialog manager sets the focus to the first control item in the dialog item list. In most cases, you'll want to add controls to your dialog boxes with the dialog editor.

See Also Windows Common Controls and MFC Classes


Deriving Controls from a Standard Control

Home | Sample

As with any CWnd-derived class, you can modify a control's behavior by deriving a new class from an existing control class.

To create a derived control class

  1. Derive your class from an existing control class and optionally override the Create member function so that it provides the necessary arguments to the base-class Create function.

  2. Use ClassWizard to provide message-handler member functions and message-map entries to modify the control's behavior in response to specific Windows messages.

  3. Provide new member functions to extend the functionality of the control (optional).

Using a derived control in a dialog box requires extra work. The types and positions of controls in a dialog box are normally specified in a dialog-template resource. If you create a derived control class, you cannot specify it in a dialog template since the resource compiler knows nothing about your derived class.

To place your derived control in a dialog box

  1. Embed an object of the derived control class in the declaration of your derived dialog class.

  2. Override the OnInitDialog member function in your dialog class to call the SubclassDlgItem member function for the derived control.

SubclassDlgItem "dynamically subclasses" a control created from a dialog template. When a control is dynamically subclassed, you hook into Windows, process some messages within your own application, then pass the remaining messages on to Windows. For more information, see the SubclassDlgItem member function of class CWnd in the Class Library Reference. The following example shows how you might write an override of OnInitDialog to call SubclassDlgItem:

BOOL CMyDialog::OnInitDialog()
{
    CDialog::OnInitDialog();
    m_wndMyBtn.SubclassDlgItem(IDC_MYBTN, this);
    return TRUE;
}

Because the derived control is embedded in the dialog class, it will be constructed when the dialog box is constructed, and it will be destroyed when the dialog box is destroyed. Compare this code to the example in Adding Controls By Hand.

See Also Windows Common Controls and MFC Classes


Using a Common Control as a Child Window

Home | Sample

Any of the Windows common controls can be used as a child window of any other window. The following procedure describes how to create a common control dynamically and then work with it.

To use a common control as a child window

  1. Define the control in the related class or handler.

  2. Use the control's override of the CWnd::Create method to create the Windows control.

  3. After the control has been created (as early as the OnCreate handler if you subclass the control), you can manipulate the control using its member functions. See the descriptions of individual controls (accessible through the table Windows Common Controls and MFC Classes) for details on methods.

  4. When you are finished with the control, use CWnd::DestroyWindow to destroy the control.

See Also Windows Common Controls and MFC Classes


Receiving Notification from Common Controls

Home | Sample

Common controls are child windows that send notification messages to the parent window when events, such as input from the user, occur in the control.

The application relies on these notification messages to determine what action the user wants it to take. Most common controls send notification messages as WM_NOTIFY messages. Windows 3.x controls send most notification messages as WM_COMMAND messages. CWnd::OnNotify is the handler for the WM_NOTIFY message. As with CWnd::OnCommand, the implementation of OnNotify dispatches the notification message to OnCmdMsg for handling in message maps. The message-map entry for handling notifications is ON_NOTIFY. For more information, see Technical Note 61: ON_NOTIFY and WM_NOTIFY Messages.

Alternately, a derived class can handle its own notification messages using "message reflection." For more information, see Technical Note 62: Message Reflection for Windows Controls.

See Also Windows Common Controls and MFC Classes


Using CAnimateCtrl

Home | Overview | Sample

An animation control, represented by the class CAnimateCtrl, is a window that displays a clip in AVI (Audio Video Interleaved) format — the standard Windows video/audio format. An AVI clip is a series of bitmap frames, like a movie.

Since your thread continues executing while the AVI clip is displayed, one common use for an animation control is to indicate system activity during a lengthy operation. For example, the Find dialog box of the Windows 95 Explorer displays a moving magnifying glass as the system searches for a file.

Animation controls can only play simple AVI clips, and they do not support sound. (For a complete list of limitations, see CAnimateCtrl.) Since the capabilities of an animation control are severely limited and subject to change, you should use an alternative such as the MCIWnd control if you need a control to provide multimedia playback and/or recording capabilities. For more information about the MCIWnd control, see the multimedia documentation.

What do you want to know more about?

  • Using an Animation Control

  • Notifications Sent by Animation Controls

See Also Windows Common Controls and MFC Classes


Using an Animation Control

Home | Overview | Sample

Typical usage of an animation control follows the pattern below:

  • The control is created. If the control is specified in a dialog box template, creation is automatic when the dialog box is created. (You should have a CAnimateCtrl member in your dialog class that corresponds to the animation control.) Alternatively, you can use the Create member function to create the control as a child window of any window.

  • Load an AVI clip into the animation control by calling the Open member function. If your animation control is in a dialog box, a good place to do this is in the dialog class's OnInitDialog function.

  • Play the clip by calling the Play member function. If your animation control is in a dialog box, a good place to do this is in the dialog class's OnInitDialog function. Calling Play is not necessary if the animation control has the ACS_AUTOPLAY style set.

  • If you want to display portions of the clip or play it frame-by-frame, use the Seek member function. To stop a clip that is playing, use the Stop member function.

  • If you're not going to destroy the control right away, remove the clip from memory by calling the Close member function.

  • If the animation control is in a dialog box, it and the CAnimateCtrl object will be destroyed automatically. If not, you need to ensure that both the control and the CAnimateCtrl object are properly destroyed. Destroying the control automatically closes the AVI clip.

See Also Windows Common Controls and MFC Classes


Notifications Sent by Animation Controls

Home | Overview | Sample

An animation control (CAnimateCtrl) sends two different types of notification messages. The notifications are sent in the form of WM_COMMAND messages.

The ACN_START message is sent when the animation control has started playing a clip. The ACN_STOP message is sent when the animation control has finished (or stopped) playing a clip.

See Also Windows Common Controls and MFC Classes


Using CDateTimeCtrl

Home | Overview | Sample

The date and time picker control (CDateTimeCtrl) implements an intuitive and recognizable method of entering or selecting a specific date. The main interface of the control is similar in functionality to a combo box. However, if the user expands the control, a month calendar control appears (by default), allowing the user to specify a particular date. When a date is chosen, the month calendar control automatically disappears.

Note To use both the CDateTimePicker and CMonthCalCtrl classes in your project, you must include AFXDTCTL.H, usually in your project's STDAFX.H file.

What do you want to know more about?

  • Creating the Date and Time Picker Control

  • Date and Time Picker Control Examples

  • Accessing the Embedded Month Calendar Control

  • Using Callback Fields in a Date and Time Picker Control

  • Using Custom Format Strings in a Date and Time Picker Control

  • Processing Notification Messages in Date and Time Picker Controls

See Also Windows Common Controls and MFC Classes


Creating the Date and Time Picker Control

Home | Overview | Sample

How the date and time picker control is created depends on whether you are using the control in a dialog box or creating it in a nondialog window.

To use CDateTimeCtrl directly in a dialog box

  1. In the dialog editor, add a Date and Time Picker Control to your dialog template resource. Specify its control ID.

  2. Specify any styles required, using the Properties dialog box of the date and time picker control.

  3. Use ClassWizard to add a member variable of type CDateTimeCtrl with the Control property. You can use this member to call CDateTimeCtrl member functions.

  4. Use ClassWizard to map handler functions in the dialog class for any date time picker control notification messages you need to handle.

  5. In OnInitDialog, set any additional styles for the CDateTimeCtrl object.

To use CDateTimeCtrl in a nondialog window

  1. Declare the control in the view or window class.

  2. Call the control's Create member function, possibly in OnInitialUpdate, possibly as early as the parent window's OnCreate handler function (if you're subclassing the control). Set the styles for the control.

See Also Windows Common Controls and MFC Classes


Date and Time Picker Control Examples

Home | Overview | Sample

The CMNCTRL1 sample demonstrates the various attributes of the CDateTimeCtrl class. A separate page contains a date and time picker control that the user can manipulate by changing various attributes and testing the basic functionality of the control.

See Also Windows Common Controls and MFC Classes


Accessing the Embedded Month Calendar Control

Home | Overview | Sample

The embedded month calendar control object can be accessed from the CDateTimeCtrl object with a call to the GetMonthCalCtrl member function.

Note The embedded month calendar control is used only when the date and time picker control does not have the DTS_UPDOWN style set.

This is useful if you want to modify certain attributes before the embedded control is displayed. To accomplish this, handle the DTN_DROPDOWN notification, retrieve the month calendar control (using CDateTimeCtrl::GetMonthCalCtrl), and make your modifications. Unfortunately, the month calendar control is not persistent.

In other words, when the user requests the display of the month calendar control, a new month calendar control is created (before the DTN_DROPDOWN notification). The control is destroyed (after the DTN_CLOSEUP notification) when dismissed by the user. This means that any attributes you modify, before the embedded control is displayed, are lost when the embedded control is dismissed.

The following example demonstrates this procedure, using a handler for the DTN_DROPDOWN notification. The code changes the background color of the month calendar control, with a call to SetMonthCalColor, to gray. The code is as follows:

void CMyDlg::OnDropdown(NMHDR* pNMHDR, LRESULT* pResult)
{

     //set the background color of the month to gray
     COLORREF clr= RGB(100, 100, 100);
     SetMonthCalColor(MCSC_MONTHBK, clr);

     *pResult = 0;
}

As stated previously, all modifications to properties of the month calendar control are lost, with two exceptions, when the embedded control is dismissed. The first exception, the colors of the month calendar control, has already been discussed. The second exception is the font used by the month calendar control. You can modify the default font by making a call to CDateTimeCtrl::SetMonthCalFont, passing the handle of an existing font. The following example (where m_dtPicker is the date and time control object) demonstrates one possible method:

CMonthCalCtrl* pMCCtrl= NULL;

pMCCtrl= m_dtPicker.GetMonthCalCtrl();

//create and initialize the font to be used
LOGFONT logFont;

logFont.lfHeight = -12;
logFont.lfWidth = 0;
logFont.lfWeight = FW_NORMAL;
logFont.lfItalic = FALSE;
logFont.lfUnderline = FALSE;
logFont.lfStrikeOut = FALSE;
logFont.lfEscapement = 0;
logFont.lfOrientation = 0;
lstrcpy(logFont.lfFaceName, _T("Verdana"));

m_MCFont.CreateFontIndirect(&logFont);
m_dtPicker.SetMonthCalFont((HFONT)m_MCFont);

Once the font has been changed, with a call to CDateTimeCtrl::SetMonthCalFont, the new font is stored and used the next time a month calendar is to be displayed.

See Also Windows Common Controls and MFC Classes


Using Custom Format Strings in a Date and Time Picker Control

Home | Overview | Sample

By default, date and time picker controls provide three format types (each format corresponding to a unique style) for displaying the current date or time:

  • DTS_LONGDATEFORMAT Displays the date in long format, producing output like "Wednesday, January 3, 1998".

  • DTS_SHORTDATEFORMAT Displays the date in short format, producing output like "1/3/98".

  • DTS_TIMEFORMAT Displays the time in long format, producing output like "5:31:42 PM".

However, you can customize the appearance of the date or time by using a custom format string. This custom string is comprised of either existing format characters, nonformat characters, or a combination of both. Once the custom string is built, make a call to CDateTimeCtrl::SetFormat passing in your custom string. The date and time picker control will then display the current value using your custom format string.

The following example code (where m_dtPicker is the CDateTimeCtrl object) demonstrates one possible solution:

CString formatStr= _T("'Today is: 'yy'/'MM'/'dd");
m_dtPicker.SetFormat(formatStr);

In addition to custom format strings, date and time picker controls also support callback fields.

See Also Windows Common Controls and MFC Classes


Using Callback Fields in a Date and Time Picker Control

Home | Overview | Sample

In addition to the standard format characters that define date and time picker fields, you can customize your output by specifying certain parts of a custom format string as callback fields. To declare a callback field, include one or more "X" characters (ASCII Code 88) anywhere in the body of the format string. For example, the following string "'Today is: 'yy'/'MM'/'dd' (Day 'X')'"causes the date and time picker control to display the current value as the year followed by the month, date, and finally the day of the year.

Note The number of X's in a callback field does not correspond to the number of characters that will be displayed.

You can distinguish between multiple callback fields in a custom string by repeating the "X" character. Thus, the format string "XXddddMMMdd', 'yyyXXX" contains two unique callback fields, "XX" and "XXX".

Note Callback fields are treated as valid fields, so your application must be prepared to handle DTN_WMKEYDOWN notification messages.

Implementing callback fields in your date and time picker control consists of three parts:

  • Initializing the custom format string

  • Handling the DTN_FORMATQUERY notification

  • Handling the DTN_FORMAT notification

Initializing the Custom Format String

Initialize the custom string with a call to CDateTimeCtrl::SetFormat. For more information, see Using Custom Format Strings in a Date and Time Picker Control. A common place to set the custom format string is in the OnInitDialog function of your containing dialog class or OnInitalUpdate function of your containing view class.

Handling the DTN_FORMATQUERY Notification

When the control parses the format string and encounters a callback field, the application sends DTN_FORMAT and DTN_FORMATQUERY notification messages. The callback field string is included with the notifications so you can determine which callback field is being queried.

The DTN_FORMATQUERY notification is sent to retrieve the maximum allowable size in pixels of the string that will be displayed in the current callback field.

To properly calculate this value, you must calculate the height and width of the string, to be substituted for the field, using the control's display font. The actual calculation of the string is easily achieved with a call to the ::GetTextExtentPoint32 Win32 function. Once the size is determined, pass the value back to the application and exit the handler function.

The following example is one method of supplying the size of the callback string:

NMDATETIMEFORMATQUERY* pDTFormatQuery= (NMDATETIMEFORMATQUERY *)pNMHDR;
CDC* pDC;
CFont* pFont;
CFont* pOrigFont;

//  Prepare the device context for the GetTextExtentPoint32 call.
pDC= GetDC();

pFont= GetFont();
if(!pFont)
     pFont->CreateStockObject(DEFAULT_GUI_FONT);

pOrigFont = pDC->SelectObject(pFont);

// Check to see if this is the callback segment desired. If so,
// use the longest text segment to determine the maximum
// width of the callback field, and then place the information into
// the NMDATETIMEFORMATQUERY structure.
if(!lstrcmp("X",pDTFormatQuery->pszFormat))
     ::GetTextExtentPoint32 (pDC->m_hDC, "366",
          3, &pDTFormatQuery->szMax);

// Reset the font in the device context then release the context.
pDC->SelectObject(pOrigFont);
ReleaseDC(pDC);

*pResult = 0;

Once the size of the current callback field has been calculated, you must supply a value for the field. This is done in the handler for the DTN_FORMAT notification.

Handling the DTN_FORMAT Notification

The DTN_FORMAT notification is used by the application to request the character string that will be substituted. The following example demonstrates one possible method:

NMDATETIMEFORMAT* pDTFormat= (NMDATETIMEFORMAT *)pNMHDR;

COleDateTime oCurTime;
m_dtPicker.GetTime(oCurTime);

wsprintf(pDTFormat->pszDisplay,
    "%d",oCurTime.GetDayOfYear());

*pResult = 0;

Note The pointer to the NMDATETIMEFORMAT structure is found by casting the first parameter of the notification handler to the proper type.

See Also Windows Common Controls and MFC Classes


Processing Notification Messages in Date and Time Picker Controls

Home | Overview | Sample

As users interact with the date and time picker control, the control (CDateTimeCtrl) sends notification messages to its parent window, usually a view or dialog object. Handle these messages if you want to do something in response. For example, when the user opens the date and time picker to display the embedded month calendar control, the DTN_DROPDOWN notification is sent.

Use WizardBar or ClassWizard to add notification handlers to the parent class for those messages you want to implement.

The following list describes the various notifications sent by the date and time picker control.

  • DTN_DROPDOWN Notifies the parent that the embedded month calendar control is about to be displayed. This notification is only sent when the DTS_UPDOWN style has not been set. For more information on this notification, see Accessing the Embedded Month Calendar Control.

  • DTN_CLOSEUP Notifies the parent that the embedded month calendar control is about to be closed. This notification is only sent when the DTS_UPDOWN style has not been set.

  • DTN_DATETIMECHANGE Notifies the parent that a change has occurred in the control.

  • DTN_FORMAT Notifies the parent that text is needed to be displayed in a callback field. For more information on this notification and callback fields, see Using Callback Fields in a Date and Time Picker Control.

  • DTN_FORMATQUERY Requests the parent to supply the maximum allowable size of the string that will be displayed in a callback field. Handling this notification allows the control to properly display output at all times, reducing flicker within the control's display. For more information on this notification, see Using Callback Fields in a Date and Time Picker Control.

  • DTN_USERSTRING Notifies the parent that the user has finished editing the contents of the date and time picker control. This notification is only sent when the DTS_APPCANPARSE style has been set.

  • DTN_WMKEYDOWN Notifies the parent when the user types in a callback field. Handle this notification to emulate the same keyboard response supported for non-callback fields in a date and time picker control. For more information on this notification, see Supporting Callback Fields in a DTP Control in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Using CComboBoxEx

Home | Overview | Sample

The extended combo box control is an extension of the standard combo box control that provides native support for item images. These images can be used to indicate the status of individual items in the combo box, such as the currently selected and unselected items. To make item images easily accessible, the control provides image list support.

Use this control to provide the functionality of a combo box without having to manually draw item graphics.

What do you want to know more about?

  • Creating an Extended Combo Box Control

  • Using Image Lists in an Extended Combo Box Control

  • Setting the Images for an Individual Item

  • Processing Notification Messages in Extended Combo Box Controls

See Also Windows Common Controls and MFC Classes


Creating an Extended Combo Box Control

Home | Overview | Sample

How the extended combo box control is created depends on whether you are using the control in a dialog box or creating it in a nondialog window.

To use CComboBoxEx directly in a dialog box

  1. In the dialog editor, add an Extended Combo Box control to your dialog template resource. Specify its control ID.

  2. Specify any styles required, using the Properties dialog box of the extended combo box control.

  3. Use ClassWizard to add a member variable of type CComboBoxEx with the Control property. You can use this member to call CComboBoxEx member functions.

  4. Use ClassWizard to map handler functions in the dialog class for any extended combo box control notification messages you need to handle.

  5. In OnInitDialog, set any additional styles for the CComboBoxEx object.

To use CComboBoxEx in a nondialog window

  1. Define the control in the view or window class.

  2. Call the control's Create member function, possibly in OnInitialUpdate, possibly as early as the parent window's OnCreate handler function. Set the styles for the control.

See Also Windows Common Controls and MFC Classes


Using Image Lists in an Extended Combo Box Control

Home | Overview | Sample

The main feature of extended combo box controls is the ability to associate images from an image list with individual items in a combo box control. Each item is able to display three different images: one for its selected state, one for its nonselected state, and a third for an overlay image.

The following procedure associates an image list with an extended combo box control:

To associate an image list with an extended combo box control

  1. Construct a new image list (or use an existing image list object), using the CImageList constructor and storing the resultant pointer.

  2. Initialize the new image list object by calling CImageList::Create. The following code is one example of this call.
    m_pImageList->Create(16, 16, ILC_COLOR, 2, 2);
  3. Add optional images for each possible state: selected or nonselected, and an overlay. The following code adds three predefined images.
    m_pImageList->Add(pApp->m_hIconSelected);
m_pImageList->Add(pApp->m_hIconNotSelected);
m_pImageList->Add(pApp->m_hIconOverlay);
  4. Associate the image list with the control with a call to CComboBoxEx::SetImageList.

Once the image list has been associated with the control, you can individually specify the images each item will use for the three possible states. For more information, see Setting the Images for an Individual Item.

See Also Windows Common Controls and MFC Classes


Setting the Images for an Individual Item

Home | Overview | Sample

The different types of images used by the extended combo box item are determined by the values in the iImage, iSelectedImage, and iOverlay members of the COMBOBOXEXITEM structure. Each value is the index of an image in the associated image list of the control. By default, these members are set to 0, causing the control to display no image for the item. If you want to use images for a specific item, you can modify the structure accordingly, either when inserting the combo box item or by modifying an existing combo box item.

Setting the Image for a New Item

If you are inserting a new item, initialize the iImage, iSelectedImage, and iOverlay structure members with the proper values and then insert the item with a call to CComboBoxEx::InsertItem.

The following example inserts a new extended combo box item (cbi) into the extended combo box control (m_comboEx), supplying indices for all three image states:

COMBOBOXEXITEM     cbi;
CString            str;
int                nItem;

cbi.mask = CBEIF_IMAGE | CBEIF_INDENT | CBEIF_OVERLAY |
     CBEIF_SELECTEDIMAGE | CBEIF_TEXT;

cbi.iItem = i;
str.Format(_T("Item %02d"), i);
cbi.pszText = (LPTSTR)(LPCTSTR)str;
cbi.cchTextMax = str.GetLength();
cbi.iImage = 0;
cbi.iSelectedImage = 1;
cbi.iOverlay = 2;
cbi.iIndent = (i & 0x03);   //Set indentation according
                            //to item position

nItem = m_comboEx.InsertItem(&cbi);
ASSERT(nItem == i);

Setting the Image for an Existing Item

If you are modifying an existing item, you need to work with the mask member of a COMBOBOXEXITEM structure.

To modify an existing item to use images

  1. Declare a COMBOBOXEXITEM structure and set the mask data member to the values you are interested in modifying.

  2. Using this structure, make a call to CComboBoxEx::GetItem.

  3. Modify the mask, iImage, and iSelectedImage members of the newly returned structure, using the appropriate values.

  4. Make a call to CComboBoxEx::SetItem, passing in the modified structure.

The following example demonstrates this procedure by swapping the selected and unselected images of the third extended combo box item:

COMBOBOXEXITEM     cbi;
CString            str;
int                nItem;

cbi.mask = CBEIF_IMAGE | CBEIF_SELECTEDIMAGE;
cbi.iItem = 2;
m_comboEx.GetItem(&cbi);

cbi.iImage = 1;
cbi.iSelectedImage = 0;
nItem = m_comboEx.SetItem(&cbi);
ASSERT(nItem != 0);

See Also Windows Common Controls and MFC Classes


Processing Notification Messages in Extended Combo Box Controls

Home | Overview | Sample

As users interact with the extended combo box, the control (CComboBoxEx) sends notification messages to its parent window, usually a view or dialog object. Handle these messages if you want to do something in response. For example, when the user activates the drop-down list or clicks in the control's edit box, the CBEN_BEGINEDIT notification is sent.

Use WizardBar or ClassWizard to add notification handlers to the parent class for those messages you want to implement.

The following list describes the various notifications sent by the extended combo box control.

  • CBEN_BEGINEDIT Sent when the user activates the drop-down list or clicks in the control's edit box.

  • CBEN_DELETEITEM Sent when an item has been deleted.

  • CBEN_DRAGBEGIN Sent when the user begins dragging the image of the item displayed in the edit portion of the control.

  • CBEN_ENDEDIT Sent when the user has concluded an operation within the edit box or has selected an item from the control's drop-down list.

  • CBEN_GETDISPINFO Sent to retrieve display information about a callback item.

  • CBEN_INSERTITEM Sent when a new item has been inserted in the control.

See Also Windows Common Controls and MFC Classes


Using CHeaderCtrl

Home | Overview | Sample

Use a header control, represented by class CHeaderCtrl, to display column headers for a columnar list. For example, a header control would be useful for implementing column controls in a spreadsheet.

The header control is usually divided into parts, called "header items," each bearing a title for the associated column of text or numbers. Depending on the styles you set, you can provide a number of direct ways for users to manipulate the header items.

Note CListCtrl provides an embedded header control, and CListView encapsulates CListCtrl in an MFC class. In general, think of using CHeaderCtrl to label lists that you intend to draw yourself.

What do you want to know more about?

  • Header Control and List Control

  • Header Control Examples

  • Header Items in a Header Control

  • Making Owner-Drawn Header Controls

  • Working with a Header Control

  • Creating the Header Control

  • Adding Items to the Header Control

  • Processing Header-Control Notifications

See Also Windows Common Controls and MFC Classes


Header Control and List Control

Home | Overview | Sample

In most cases, you will use the header control that is embedded in a CListCtrl or CListView object. However, there are cases where a separate header control object is desirable, such as manipulating data, arranged in columns or rows, in a CView-derived object. In these cases, you need greater control over the appearance and default behavior of an embedded header control.

In the common case that you want a header control to provide standard, default behavior, you may want to use CListCtrl or CListView instead. Use CListCtrl when you want the functionality of a default header control, embedded in a list view common control. Use CListView when you want the functionality of a default header control, embedded in a view object.

Note These controls only include a built-in header control if the list view control is created using the LVS_REPORT style.

In most cases, the appearance of the embedded header control can be modified by changing the styles of the containing list view control. In addition, information about the header control can be obtained through member functions of the parent list view control. However, for complete control, and access, to the attributes and styles of the embedded header control, it is recommended that a pointer to the header control object be obtained.

The embedded header control object can be accessed from either CListCtrl or CListView with a call to the respective class's GetHeaderCtrl member function. The following code demonstrates this:

CListCtrl& refList = GetListCtrl();
CHeaderCtrl* pCtrl = refList.GetHeaderCtrl();
ASSERT(pCtrl != NULL);
//perform any needed operations on the header
//using pHeader

What do you want to know more about?

  • Using image lists with header controls

See Also Windows Common Controls and MFC Classes


Header Control Examples

Home | Overview | Sample

The LISTHDR sample application demonstrates various attributes and styles for a list view control, implemented with a CListCtrl object, and the embedded header control, implemented with a CHeaderCtrl object.

For examples of header controls, see the right-hand pane in Explorer and the topic Header Controls in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Header Items in a Header Control

Home | Overview | Sample

You have considerable control over the appearance and behavior of the header items that make up a header control (CHeaderCtrl). Each header item can have a string, a bitmapped image, an image from an associated image list, or an application-defined 32-bit value associated with it. The string, bitmap, or image is displayed in the header item.

You can customize the appearance and contents of new items when they are created by making a call CHeaderCtrl::InsertItem or by modifying an existing item, with a call to CHeaderCtrl::GetItem and CHeaderCtrl::SetItem.

What do you want to know more about?

  • Customizing the header item's appearance

  • Ordering items in the header control

  • Providing drag-and-drop support for the header items

  • Using image lists with header controls


Customizing the Header Item's Appearance

Home | Overview | Sample

By setting the dwStyle parameter when you first create a header control (CHeaderCtrl::Create), you can define the appearance and behavior of header items or of the header control itself.

Here is a sampling of the styles you can set, and their purpose:

  • To make a header item look like a pushbutton, use the HDS_BUTTONS style.

    Use this style if you want to carry out actions in response to mouse clicks on a header item, such as sorting data by a particular column, as is done in Microsoft Outlook.

  • To give the header items a "hot tracking" appearance when the mouse cursor passes over them, use the HDS_HOTTRACK style.

    Hot tracking displays a 3D outline as the pointer passes over an item in an otherwise flat bar.

  • To indicate that the header control should be hidden, use the HDS_HIDDEN style.

    The HDS_HIDDEN style indicates that the header control is intended to be used as a data container and not a visual control. This style does not automatically hide the control but, instead, affects the behavior of CHeaderCtrl::Layout. The value returned in the cy member of the WINDOWPOS structure will be zero indicating that the control should not be visible to the user.

For more information about these properties, see Items in the Platform SDK. For information about adding items to a header control, see Adding Items to the Header Control.

See Also Windows Common Controls and MFC Classes


Providing Drag-and-Drop Support for Header Items

Home | Overview | Sample

To provide drag-and-drop support for header items, specify the HDS_DRAGDROP style. Drag-and-drop support for header items gives the user the ability to reorder the header items of a header control. The default behavior provides a semitransparent drag image of the header item being dragged and a visual indicator of the new position, if the header item is dropped.

As with common drag-and-drop functionality, you can extend the default drag-and-drop behavior by handling the HDN_BEGINDRAG and HDN_ENDDRAG notifications. You can also customize the appearance of the drag image by overriding the CHeaderCtrl::CreateDragImage member function.

Note If you are providing drag-and-drop support for an embedded header control in a list control, see the Extended Style section in the Changing List Control Styles topic.


Using Image Lists with Header Controls

Home | Overview | Sample

Header items have the ability to display an image within a header item. This image, stored in an associated image list, is 16 x 16 pixels and has the same characteristics as the icon images used in a list view control. In order to implement this behavior successfully, you must first create and initialize the image list, associate the list with the header control, and then modify the attributes of the header item that will display the image.

The following procedure illustrates the details, using a pointer to a header control (m_pHdrCtrl) and a pointer to an image list (m_pHdrImages).

To display an image in a header item

  1. Construct a new image list (or use an existing image list object) using the CImageList constructor, storing the resultant pointer.

  2. Initialize the new image list object by calling CImageList::Create. The following code is one example of this call.
    m_pHdrImages->Create(16, 16, ILC_MASK, 2, 2);
  3. Add the images for each header item. The following code adds two predefined images.
    m_pHdrImages->Add(pApp->LoadIcon(IDI_ICONHDR1));
m_pHdrImages->Add(pApp->LoadIcon(IDI_ICONHDR2));
  4. Associate the image list with the header control with a call to CHeaderCtrl::SetImageList.

  5. Modify the header item to display an image from the associated image list. The following example assigns the first image, from m_phdrImages, to the first header item, m_pHdrCtrl.
    HDITEM    curItem;

m_pHdrCtrl->SetImageList(m_pHdrImages);
m_pHdrCtrl->GetItem(0, &curItem);
curItem.mask= HDI_IMAGE | HDI_FORMAT;
curItem.iImage= 0;
curItem.fmt= HDF_LEFT | HDF_IMAGE | HDF_STRING;
m_pHdrCtrl->SetItem(0, &curItem);

For detailed information on the parameter values used, consult the pertinent CHeaderCtrl.

Note It is possible to have multiple controls using the same image list. For instance, in a standard list view control, there could be an image list (of 16 x 16 pixel images) used by both the small icon view of a list view control and the header items of the list view control.


Making Owner-Drawn Header Controls

Home | Overview | Sample

You can define individual items of a header control (CHeaderCtrl) to be owner-drawn items. For more information, see Owner-Drawn Header Controls in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Working with a Header Control

Home | Overview | Sample

The easy way to use a header control (CHeaderCtrl) is in conjunction with a list control; see Using CListCtrl later in this article family. You can also use a header control by itself. MFC calls InitCommonControls for you. The key tasks are as follows:

  • Creating the header control

  • Adding items to the header control

  • Ordering items in the header control

  • Processing header-control notifications

If the header control object is embedded in a parent view or dialog class, the control is destroyed when the parent is destroyed.

See Also Windows Common Controls and MFC Classes


Creating the Header Control

Home | Overview | Sample

The header control is not directly available in the dialog editor (although you can add a list control, which includes a header control). ClassWizard doesn't support adding data members of type CHeaderCtrl.

To put a header control in a dialog box

  1. Manually embed a member variable of type CHeaderCtrl in your dialog class.

  2. In OnInitDialog, create and set the styles for the CHeaderCtrl, position it, and display it.

  3. Add items to the header control.

  4. Use ClassWizard to map handler functions in the dialog class for any header-control notification messages you need to handle.

To put a header control in a view (not a CListView)

  1. Embed a CHeaderCtrl object in your view class.

  2. Style, position, and display the header control window in the view's OnInitialUpdate member function.

  3. Add items to the header control.

  4. Use ClassWizard to map handler functions in the view class for any header-control notification messages you need to handle.

In either case, the embedded control object is created when the view or dialog object is created. Then you must call CHeaderCtrl::Create to create the control window. To position the control, call CHeaderCtrl::Layout to determine the control's initial size and position and SetWindowPos to set the position you want. Then add items as described in Adding Items to the Header Control.

For more information, see Creating a Header Control in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Adding Items to the Header Control

Home | Overview | Sample

After creating your header control (CHeaderCtrl) in its parent window, add as many "header items" as you need: usually one per column.

To add a header item

  1. Prepare an HD_ITEM structure.

  2. Call CHeaderCtrl::InsertItem, passing the structure.

  3. Repeat steps 1 and 2 for additional items.

For more information, see Adding an Item to a Header Control in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Ordering Items in the Header Control

Home | Overview | Sample

Once you've added items to a header control, you can manipulate or get information about their order with the following functions:

  • CHeaderCtrl::GetOrderArray and CHeaderCtrl::SetOrderArray

    Retrieves and sets the left-to-right order of header items.

  • CHeaderCtrl::OrderToIndex.

    Retrieves the index value for a specific header item.

In addition to the previous member functions, the HDS_DRAGDROP style allows the user to drag and drop header items within the header control. For more information, see Providing Drag-and-Drop Support for Header Items.


Processing Header-Control Notifications

Home | Overview | Sample

In your view or dialog class, use ClassWizard to create an OnChildNotify handler function with a switch statement for any header-control (CHeaderCtrl) notification messages you want to handle. Notifications are sent to the parent window when the user clicks or double-clicks a header item, drags a divider between items, and so on.

The notification messages associated with a header control are listed in Header Control Notification Messages in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Using CHotKeyCtrl

Home | Overview | Sample

A hot key control, represented by class CHotKeyCtrl, is a window that displays a text representation of the key combination the user types into it, such as CTRL+SHIFT+Q. It also maintains an internal representation of this key in the form of a virtual key code and a set of flags that represent the shift state. The hot key control does not actually set the hot key — doing that is up to your program.

Use a hot key control to get a user's input for which hot key to associate with a window or thread. Hot key controls are often used in dialog boxes, such as you might display when asking the user to assign a hot key. It is your program's responsibility to retrieve the values describing the hot key from the hot key control and to call the appropriate functions to associate the hot key with a window or thread.

What do you want to know more about?

  • Using a Hot Key Control

  • Setting a Hot Key

  • Global Hot Keys

  • Thread-Specific Hot Keys

See Also Windows Common Controls and MFC Classes


Using a Hot Key Control

Home | Overview | Sample

Typical usage of a hot key control follows the pattern below:

  • The control is created. If the control is specified in a dialog box template, creation is automatic when the dialog box is created. (You should have a CHotKeyCtrl member in your dialog class that corresponds to the hot key control.) Alternatively, you can use the Create member function to create the control as a child window of any window.

  • If you want to set a default value for the control, call the SetHotKey member function. If you want to prohibit certain shift states, call SetRules. For controls in a dialog box, a good time to do this is in the dialog box's OnInitDialog function.

  • The user interacts with the control by pressing a hot key combination when the hot key control has focus. The user then somehow indicates that this task is complete, perhaps by clicking a button in the dialog box.

  • When your program is notified that the user has selected a hot key, it should use the member function GetHotKey to retrieve the virtual key and shift state values from the hot key control.

  • Once you know what key the user selected, you can set the hot key using one of the methods described in Setting a Hot Key.

  • If the hot key control is in a dialog box, it and the CHotKeyCtrl object will be destroyed automatically. If not, you need to ensure that both the control and the CHotKeyCtrl object are properly destroyed.

See Also Windows Common Controls and MFC Classes


Setting a Hot Key

Home | Overview | Sample

Your application can use the information provided by a hot key (CHotKeyCtrl) control in one of two ways:

  • Set up a global hot key for activating a nonchild window by sending a WM_SETHOTKEY message to the window to be activated.

  • Set up a thread-specific hot key by calling the Windows function RegisterHotKey.

See Also Windows Common Controls and MFC Classes


Global Hot Keys

Home | Overview | Sample

A global hot key is associated with a particular nonchild window. It allows the user to activate the window from any part of the system. An application sets a global hot key for a particular window by sending the WM_SETHOTKEY message to that window. For instance, if m_HotKeyCtrl is the CHotKeyCtrl object and pMainWnd is a pointer to the window to be activated when the hot key is pressed, you could use the following code to associate the hot key specified in the control with the window pointed to by pMainWnd.

WORD wKeyAndShift = m_HotKeyCtrl.GetHotKey( );
pMainWnd->SendMessage( WM_SETHOTKEY, wKeyAndShift );

Whenever the user presses a global hot key, the window specified receives a WM_SYSCOMMAND message that specifies SC_HOTKEY as the type of the command. This message also activates the window that receives it. Because this message does not include any information on the exact key that was pressed, using this method does not allow distinguishing between different hot keys that may be attached to the same window. The hot key remains valid until the application that sent WM_SETHOTKEY exits.

See Also Windows Common Controls and MFC Classes


Thread-Specific Hot Keys

Home | Overview | Sample

An application sets a thread-specific hot key (CHotKeyCtrl) by using the Windows RegisterHotKey function. When the user presses a thread-specific hot key, Windows posts a WM_HOTKEY message to the beginning of a particular thread's message queue. The WM_HOTKEY message contains the virtual key code, shift state, and user-defined ID of the specific hot key that was pressed. For more information on this method, see RegisterHotKey. Note that the shift state flags used in the call to RegisterHotKey are not the same as those returned by the GetHotKey member function; you'll have to translate these flags before calling RegisterHotKey.

See Also Windows Common Controls and MFC Classes


Using CImageList

Home | Overview | Sample

An image list, represented by class CImageList, is a collection of same-sized images, each of which can be referred to by its index. Image lists are used to efficiently manage large sets of icons or bitmaps. Image lists are not themselves controls since they are not windows; however, they are used with several different types of controls, including list controls (CListCtrl), tree controls (CTreeCtrl), and tab controls (CTabCtrl).

All images in an image list are contained in a single, wide bitmap in screen-device format. An image list may also include a monochrome bitmap that contains masks used to draw images transparently (icon style). CImageList provides member functions that enable you to draw images, create and destroy image lists, add and remove images, replace images, merge images, and drag images.

What do you want to know more about?

  • Types of Image Lists

  • Using an Image List

  • Manipulating Image Lists

  • Drawing Images from an Image List

  • Image Overlays in Image Lists

  • Dragging Images from an Image List

  • Image Information in Image Lists

See Also Windows Common Controls and MFC Classes


Types of Image Lists

Home | Overview | Sample

There are two types of image lists (CImageList): nonmasked and masked. A "nonmasked image list" consists of a color bitmap that contains one or more images. A "masked image list" consists of two bitmaps of equal size. The first is a color bitmap that contains the images, and the second is a monochrome bitmap that contains a series of masks — one for each image in the first bitmap.

One of the overloads of the Create member function takes a flag to indicate whether or not the image list is masked. (The other overloads create masked image lists.)

When a nonmasked image is drawn, it is simply copied into the target device context; that is, it is drawn over the existing background color of the device context. When a masked image is drawn, the bits of the image are combined with the bits of the mask, typically producing transparent areas in the bitmap where the background color of the target device context shows through. You can specify several drawing styles when drawing a masked image. For example, you can specify that the image be dithered to indicate a selected object.

See Also Windows Common Controls and MFC Classes


Using an Image List

Home | Overview | Sample

Typical usage of an image list follows the pattern below:

  • Construct a CImageList object and call one of the overloads of its Create function to create an image list and attach it to the CImageList object.

  • If you didn't add images when you created the image list, add images to the image list by calling the Add or Read member function.

  • Associate the image list with a control by calling the appropriate member function of that control, or draw images from the image list yourself using the image list's Draw member function.

  • Perhaps allow the user to drag an image, using the image list's built-in support for dragging.

Note If the image list was created with the new operator, you must destroy the CImageList object when you are done with it.

See Also Windows Common Controls and MFC Classes


Manipulating Image Lists

Home | Overview | Sample

The Replace member function replaces an image in an image list (CImageList) with a new image. This function is also useful if you need to dynamically increase the number of images in an image list object. The SetImageCount function dynamically changes the number of images stored in the image list. If you increase the size of the image list, call Replace to add images to the new image slots. If you decrease the size of the image list, the images beyond the new size are freed.

The Remove member function removes an image from an image list. The Copy member function can copy or swap images within an image list. This function allows you to indicate whether the source image should be copied to the destination index or the source and destination images should be swapped.

To create a new image list by merging two image lists, use the appropriate overload of the Create member function. This overload of Create merges the first image of the existing image lists, storing the resultant image in a new image list object. The new image is created by drawing the second image transparently over the first. The mask for the new image is the result of performing a logical-OR operation on the bits of the masks for the two existing images.

This is repeated until all images are merged and added to the new image list object.

You can write the image information to an archive by calling the Write member function, and read it back by calling the Read member function.

The GetSafeHandle, Attach, and Detach member functions allow you to manipulate the handle of the image list attached to the CImageList object, while the DeleteImageList member function deletes the image list without destroying the CImageList object.

See Also Windows Common Controls and MFC Classes


Drawing Images from an Image List

Home | Overview | Sample

To draw an image, use the CImageList::Draw member function. You'll specify a pointer to a device context object, the index of the image to draw, the location in the device context at which to draw the image, and a set of flags to indicate the drawing style.

When you specify the ILD_TRANSPARENT style, Draw uses a two-step process to draw a masked image. First, it performs a logical-AND operation on the bits of the image and the bits of the mask. Then it performs a logical-XOR operation on the results of the first operation and the background bits of the destination device context. This process creates transparent areas in the resulting image; that is, each white bit in the mask causes the corresponding bit in the resulting image to be transparent.

Before drawing a masked image on a solid color background, you should use the SetBkColor member function to set the background color of the image list to the same color as the destination. Setting the color eliminates the need to create transparent areas in the image and enables Draw to simply copy the image to the destination device context, resulting in a significant increase in performance. To draw the image, specify the ILD_NORMAL style when you call Draw.

You can set the background color for a masked image list (CImageList) at any time so that it draws correctly on any solid background. Setting the background color to CLR_NONE causes images to be drawn transparently by default. To retrieve the background color of an image list, use the GetBkColor member function.

The ILD_BLEND25 and ILD_BLEND50 styles dither the image with the system highlight color. These styles are useful if you use a masked image to represent an object that the user can select. For example, you can use the ILD_BLEND50 style to draw the image when the user selects it.

A nonmasked image is copied to the destination device context using the SRCCOPY raster operation. The colors in the image appear the same regardless of the background color of the device context. The drawing styles specified in Draw also have no effect on the appearance of a nonmasked image.

In addition to the Draw member function, another function, DrawIndirect, extends the ability to render an image. DrawIndirect takes, as a parameter, an IMAGELISTDRAWPARAMS structure. This structure can be used to customize the rendering of the current image, including the use of raster operation (ROP) codes. For more information on ROP codes, see Raster Operation Codes and Bitmaps as Brushes in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Image Overlays in Image Lists

Home | Overview | Sample

Every image list (CImageList) includes a list of images to use as overlay masks. An "overlay mask" is an image drawn transparently over another image. Any image can be used as an overlay mask. You can specify up to four overlay masks per image list.

You add the index of an image to the list of overlay masks by using the SetOverlayImage member function, the index of an image, and the index of an overlay mask. Note that the indices for the overlay masks are one-based rather than zero-based.

You draw an overlay mask over an image using a single call to Draw. The parameters include the index of the image to draw and the index of an overlay mask. You must use the INDEXTOOVERLAYMASK macro to specify the index of the overlay mask. You can also specify an overlay image when calling the DrawIndirect member function.

See Also Windows Common Controls and MFC Classes


Dragging Images from an Image List

Home | Overview | Sample

CImageList includes functions for dragging an image on the screen. The dragging functions move an image smoothly, in color, and without any flashing of the cursor. Both masked and unmasked images can be dragged.

The BeginDrag member function begins a drag operation. The parameters include the index of the image to drag and the location of the hot spot within the image. The hot spot is a single pixel that the dragging functions recognize as the exact screen location of the image. Typically, an application sets the hot spot so that it coincides with the hot spot of the mouse cursor. The DragMove member function moves the image to a new location.

The DragEnter member function sets the initial position of the drag image within a window and draws the image at the position. The parameters include a pointer to the window in which to draw the image and a point that specifies the coordinates of the initial position within the window. The coordinates are relative to the window's upper-left corner, not the client area. The same is true for all of the image-dragging functions that take coordinates as parameters. This means you must compensate for the widths of window elements, such as the border, title bar, and menu bar, when specifying the coordinates. If you specify a NULL window handle when calling DragEnter, the dragging functions draw the image in the device context associated with the desktop window, and the coordinates are relative to the upper-left corner of the screen.

DragEnter locks all other updates to the given window during the drag operation. If you need to do any drawing during a drag operation, such as highlighting the target of a drag-and-drop operation, you can temporarily hide the dragged image by using the DragLeave member function. You can also use the DragShowNoLock member function.

Call EndDrag when you're done dragging the image.

The SetDragCursorImage member function creates a new drag image by combining the given image (typically a mouse cursor image) with the current drag image. Because the dragging functions use the new image during a drag operation, you should use the Windows ShowCursor function to hide the actual mouse cursor after calling SetDragCursorImage. Otherwise, the system may appear to have two mouse cursors for the duration of the drag operation.

When an application calls BeginDrag, the system creates a temporary, internal image list and copies the specified drag image to the internal list. You can retrieve a pointer to the temporary drag image list by using the GetDragImage member function. The function also retrieves the current drag position and the offset of the drag image relative to the drag position.

See Also Windows Common Controls and MFC Classes


Image Information in Image Lists

Home | Overview | Sample

CImageList includes a number of functions that retrieve information from an image list. The GetImageInfo member function fills an IMAGEINFO structure with information about a single image, including the handles of the image and mask bitmaps, the number of color planes and bits per pixel, and the bounding rectangle of the image within the image bitmap. You can use this information to directly manipulate the bitmaps for the image.

The GetImageCount member function retrieves the number of images in an image list.

You can create an icon based on an image and mask in an image list by using the ExtractIcon member function. The function returns the handle of the new icon.

See Also Windows Common Controls and MFC Classes


Using CListCtrl

Home | Overview | Sample

Use a list control to display any arrangement of icons with labels, as in the Windows Explorer, or columnar lists of text, with or without icons. For a description of the four possible "views" (not to be confused with MFC views) you can have in a list control — icon view, small icon view, list view, and report view — see Views in the CListCtrl class overview.

In some views, users can drag icons to different positions or edit icon labels. For example, see the right-hand pane in Windows Explorer, which uses a list control in a nondialog window. You can experiment with the available views in Explorer's View menu.

For related information, see List View Controls in the Platform SDK.

Note The Platform SDK refers to list controls as "list view controls." This usage of "view" does not refer to MFC view classes, particularly CListView. For more information, see List Control and List View.

What do you want to know more about?

  • List Control and List View

  • List Control Examples

  • List Items and Image Lists

  • Callback Items and the Callback Mask

  • Creating the List Control

  • Creating the Image Lists

  • Adding Columns to the Control (Report View)

  • Adding Items to the Control

  • Scrolling, Arranging, Sorting, and Finding in List Controls

  • Implementing Working Areas in List Controls

  • Processing Notification Messages in List Controls

  • Changing List Control Styles

  • Virtual List Controls

  • Destroying the List Control

See Also Windows Common Controls and MFC Classes


List Control and List View

Home | Overview | Sample

For convenience, MFC encapsulates the list control in two ways. You can use list controls:

  • Directly, by embedding a CListCtrl object in a dialog class.

  • Indirectly, by using class CListView.

CListView makes it easy to integrate a list control with the MFC document/view architecture, encapsulating the control much as CEditView encapsulates an edit control: the control fills the entire surface area of an MFC view. (The view is the control, cast to CListView.)

A CListView object inherits from CCtrlView and its base classes and adds a member function to retrieve the underlying list control. Use view members to work with the view as a view. Use the GetListCtrl member function to gain access to the list control's member functions. Use these members to:

  • Add, delete, or manipulate "items" in the list.

  • Set or get list control attributes.

To obtain a reference to the CListCtrl underlying a CListView, call GetListCtrl from your list view class:

CListCtrl& ctlList = GetListCtrl();

This article describes both ways to use the list control.

See Also Windows Common Controls and MFC Classes


List Control Examples

Home | Overview | Sample

The LISTHDR sample application demonstrates various attributes and styles for a list view control, implemented with a CListCtrl object, and the embedded header control, implemented with a CHeaderCtrl object.

In addition, the DAOVIEW sample application uses a CListView and, by extension, the underlying CListCtrl.

Tip DAOVIEW also supplies a helpful support class for working with list views. See class CListCtrlEx in the sample. Although CListCtrlEx is not a documented MFC class, you might find it useful in your own applications.

See Also Windows Common Controls and MFC Classes


List Items and Image Lists

Home | Overview | Sample

An "item" in a list control (CListCtrl) consists of an icon, a label, and possibly other information (in "subitems").

The icons for list control items are contained in image lists. One image list contains full-sized icons used in icon view. A second, optional, image list contains smaller versions of the same icons for use in other views of the control. A third optional list contains "state" images, such as check boxes, for display in front of the small icons in certain views. A fourth optional list contains images that are displayed in individual header items of the list control.

Note If a list view control is created with the LVS_SHAREIMAGELISTS style, you are responsible for destroying the image lists when they are no longer in use. Specify this style if you assign the same image lists to multiple list view controls; otherwise, more than one control might try to destroy the same image list.

For more information about list items, see List View Image Lists and Items and Subitems in the Platform SDK. Also see class CImageList in the Class Library Reference and Using CImageList in this article.

To create a list control, you need to supply image lists to be used when you insert new items into the list. The following example demonstrates this procedure, where m_pImagelist is a pointer of type CImageList and m_listctrl is a CListCtrl data member.

// create, initialize, and hook up image list
m_pImageList = new CImageList();
ASSERT(m_pImageList != NULL);    // serious allocation failure checking
m_pImageList->Create(32, 32, TRUE,   4, 4);
m_pImageList->Add(pApp->LoadIcon(IDI_ICONLIST1));
m_pImageList->Add(pApp->LoadIcon(IDI_ICONLIST2));
m_listctrl.SetImageList(m_pImageList, LVSIL_NORMAL);

However, if you don't plan to display icons in your list view or list control, you don't need image lists. See the DAOVIEW sample application for an illustration of a list view with no icons.

See Also Windows Common Controls and MFC Classes


Callback Items and the Callback Mask

Home | Overview | Sample

For each of its items, a list view control typically stores the label text, the image list index of the item's icons, and a set of bit flags for the item's state. You can define individual items as callback items, which are useful if your application already stores some of the information for an item.

You define an item as a callback item by specifying appropriate values for the pszText and iImage members of the LV_ITEM structure (see CListCtrl::GetItem). If the application maintains the item's or subitem's text, specify the LPSTR_TEXTCALLBACK value for the pszText member. If the application keeps track of the icon for the item, specify the I_IMAGECALLBACK value for the iImage member.

In addition to defining callback items, you can also modify the control's callback mask. This mask is a set of bit flags that specify the item states for which the application, rather than the control, stores the current data. The callback mask applies to all of the control's items, unlike the callback item designation, which applies to a specific item. The callback mask is zero by default, meaning that the control tracks all item states. To change this default behavior, initialize the mask to any combination of the following values:

  • LVIS_CUT The item is marked for a cut-and-paste operation.

  • LVIS_DROPHILITED The item is highlighted as a drag-and-drop target.

  • LVIS_FOCUSED The item has the focus.

  • LVIS_SELECTED The item is selected.

  • LVIS_OVERLAYMASK The application stores the image list index of the current overlay image for each item.

  • LVIS_STATEIMAGEMASK The application stores the image list index of the current state image for each item.

For further information on retrieving and setting this mask, see CListCtrl::GetCallbackMask and CListCtrl::SetCallbackMask.

See Also Windows Common Controls and MFC Classes


Creating the List Control

Home | Overview | Sample

How the list control (CListCtrl) is created depends on whether you're using the control directly or using class CListView instead. If you use CListView, the framework constructs the view as part of its document/view creation sequence. Creating the list view creates the list control as well (the two are the same thing). The control is created in the view's OnCreate handler function. In this case, the control is ready for you to add items, via a call to GetListCtrl.

To use CListCtrl directly in a dialog box

  1. In the dialog editor, add a List Control to your dialog template resource. Specify its control ID.

  2. Use ClassWizard to add a member variable of type CListCtrl with the Control property. You can use this member to call CListCtrl member functions.

  3. Use ClassWizard to map handler functions in the dialog class for any list control notification messages you need to handle.

  4. In OnInitDialog, set the styles for the CListCtrl. See Changing List Control Styles. This determines the kind of "view" you get in the control, although you can change the view later.

To use CListCtrl in a nondialog window

  1. Define the control in the view or window class.

  2. Call the control's Create member function, possibly in OnInitialUpdate, possibly as early as the parent window's OnCreate handler function (if you're subclassing the control). Set the styles for the control.

See Also Windows Common Controls and MFC Classes


Creating the Image Lists

Home | Overview | Sample

Creating image lists is the same whether you use CListView or CListCtrl.

Note You only need image lists if your list control includes the LVS_ICON style.

Use class CImageList to create one or more image lists (for full-size icons, small icons, and states). See CImageList, and see List View Image Lists in the Platform SDK.

Call CListCtrl::SetImageList for each image list; pass a pointer to the appropriate CImageList object.

See Also Windows Common Controls and MFC Classes


Adding Columns to the Control (Report View)

Home | Overview | Sample

Note The following procedure applies to either a CListView or CListCtrl object.

When a list control is in report view, columns are displayed, providing a method of organizing the various subitems of each list control item. This organization is implemented with a one-to-one correspondence between a column in the list control and the associated subitem of the list control item. For more information on subitems, see Adding Items to the Control. An example of a list control in report view is provided by the Details view in Windows 95 Explorer. The first column lists folder, file icons, and labels. Other columns list file size, file type, date last modified, and so on.

Even though columns can be added to a list control at any time, the columns are visible only when the control has the LVS_REPORT style bit turned on.

Each column has an associated header item (see CHeaderCtrl) object that labels the column and allows users to resize the column. For a code example, see the DAOVIEW sample application.

If your list control supports a report view, you need to add a column for each possible subitem in a list control item. Add a column by preparing an LV_COLUMN structure and then making a call to InsertColumn. After adding the necessary columns (sometimes referred to as header items), you can reorder them using member functions and styles belonging to the embedded header control. For more information, see Ordering Items in the Header Control.

Note If the list control is created with the LVS_NOCOLUMNHEADER style, any attempt to insert columns will be ignored.

See Also Windows Common Controls and MFC Classes


Adding Items to the Control

Home | Overview | Sample

To add items to the list control (CListCtrl), call one of several versions of the InsertItem member function, depending on what information you have. One version takes a LV_ITEM structure that you prepare. Because the LV_ITEM structure contains numerous members, you have greater control over the attributes of the list control item.

Two important members (in regard to the report view) of the LV_ITEM structure are the iItem and iSubItem members. The iItem member is the zero-based index of the item the structure is referencing and the iSubItem member is the one-based index of a subitem, or zero if the structure contains information about an item. With these two members you determine, per item, the type and value of subitem information that is displayed when the list control is in report view. For more information, see CListCtrl::SetItem.

Additional members specify the item's text, icon, state, and item data. "Item data" is an application-defined value associated with a list view item. For more information about the LV_ITEM structure, see CListCtrl::GetItem.

Other versions of InsertItem take one or more separate values, corresponding to members in the LV_ITEM structure, allowing you to initialize only those members you want to support. Generally, the list control manages storage for list items, but you can store some of the information in your application instead, using "callback items." For more information, see Callback Items and the Callback Mask in this article and Callback Items and the Callback Mask in the Platform SDK.

For more information, see Items and Subitems

See Also Windows Common Controls and MFC Classes


Scrolling, Arranging, Sorting, and Finding in List Controls

Home | Overview | Sample

List controls (CListCtrl) are scrollable by default. For more information, see Scroll Position in the Platform SDK and the Scroll member function.

You can call CListCtrl member functions to arrange list items in the control, sort items, and find particular items. For more information, see Arranging, Sorting, and Finding in the Platform SDK and the CListCtrl members Arrange, SortItems, and FindItem.

See Also Windows Common Controls and MFC Classes


Implementing Working Areas in List Controls

Home | Overview | Sample

By default, a list control arranges all items in a standard grid fashion. However, another method is supported, working areas, that arranges the list items into rectangular groups. For an image of a list control that implements working areas, see List View Working Areas in the Platform SDK.

Note Working areas are visible only when the list control is in icon or small icon mode. However, any current working areas are maintained if the view is switched to the report or list mode.

Working areas can be used to display an empty border (on the left, top and/or right of the items), or cause a horizontal scroll bar to be displayed when there normally wouldn't be one. Another common usage is to create multiple working areas to which items can be moved or dropped. With this method, you could create areas in a single view that have different meanings. The user could then categorize the items by placing them in a different area. An example of this would be a view of a file system that has an area for read/write files and another area for read-only files. If a file item were moved into the read-only area, it would automatically become read-only. Moving a file from the read-only area into the read/write area would make the file read/write.

CListCtrl provides several member functions for creating and managing working areas in your list control. GetWorkAreas and SetWorkAreas retrieve and set an array of CRect objects (or RECT structures), which store the currently implemented working areas for your list control. In addition, GetNumberOfWorkAreas retrieves the current number of working areas for your list control (by default, zero).

Items and Working Areas

When a working area is created, items that lie within the working area become members of it. Similarly, if an item is moved into a working area, it becomes a member of the working area to which it was moved. If an item does not lie within any working area, it automatically becomes a member of the first (index 0) working area. If you want to create an item and have it placed within a specific working area, you will need to create the item and then move it into the desired working area with a call to SetItemPosition. The second example below demonstrates this technique.

The following example implements four working areas (rcWorkAreas), of equal size with a 10-pixel-wide border around each working area, in a list control (m_listctrl).

CRect curRect;
CSize size;

size= m_listctrl.ApproximateViewRect();
size.cx+= 100;
size.cy+= 100;

CRect rcWorkAreas[4];

rcWorkAreas[0].SetRect(0, 0, (size.cx / 2) - 5, (size.cy / 2) - 5);
rcWorkAreas[1].SetRect((size.cx / 2) + 5, 0, size.cx, (size.cy / 2) - 5);
rcWorkAreas[2].SetRect(0, (size.cy / 2) + 5, (size.cx / 2) - 5, size.cy);
rcWorkAreas[3].SetRect((size.cx / 2) + 5, (size.cy / 2) + 5, size.cx, size.cy);

//set work areas
m_listctrl.SetWorkAreas(4, rcWorkAreas);

The call to ApproximateViewRect was made to get an estimate of the total area required to display all items in one region. This estimate is then divided into four regions and padded with a 5-pixel-wide border.

The next example assigns the existing list items to each group (rcWorkAreas) and refreshes the control view (m_listctrl) to complete the effect.

// set insertion points for each work area
CPoint     rgptWork[4];
for (int i = 0; i < 4; i++)
{
     rgptWork[i].x = rcWorkAreas[i].left + 10;
     rgptWork[i].y = rcWorkAreas[i].top + 10;
}
// now move all the items to the different quadrants
for (i = 0; i < 20; i++)
     m_listctrl.SetItemPosition(i, rgptWork[i % 4]);

// force the control to rearrange the shuffled items
m_listctrl.Arrange(LVA_DEFAULT);

See Also Windows Common Controls and MFC Classes


Processing Notification Messages in List Controls

Home | Overview | Sample

As users click column headers, drag icons, edit labels, and so on, the list control (CListCtrl) sends notification messages to its parent window. Handle these messages if you want to do something in response. For example, when the user clicks a column header, you might want to sort the items based on the contents of the clicked column, as in Microsoft Outlook.

Process WM_NOTIFY messages from the list control in your view or dialog class. Use WizardBar or ClassWizard to create an OnChildNotify handler function with a switch statement based on which notification message is being handled.

For a list of the notifications a list control can send to its parent window, see List View Control Notification Messages in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Changing List Control Styles

Home | Overview | Sample

You can change the window style of a list control (CListCtrl) at any time after you create it. By changing the window style, you change the kind of view the control uses. For example, to emulate the Explorer, you might supply menu items or toolbar buttons for switching the control between different views: icon view, list view, and so on.

For example, when the user selects your menu item, you could make a call to GetWindowLong to retrieve the current style of the control and then call SetWindowLong to reset the style. For more information, see Using List View Controls in the Platform SDK.

Available styles are listed in Create. The styles LVS_ICON, LVS_SMALLICON, LVS_LIST, and LVS_REPORT designate the four list control views.

Extended Styles

In addition to the standard styles for a list control, there is another set, referred to as extended styles. These styles, discussed in Extended List View Styles in the Platform SDK, provide a variety of useful features that customize the behavior of your list control. To implement the behavior of a certain style (such as hover selection), make a call to CListCtrl::SetExtendedStyle, passing the needed style. The following example demonstrates the function call:

m_myListCtrl.SetExtendedStyle(LVS_EX_TRACKSELECT | LVS_EX_ONECLICKACTIVATE);

Note For hover selection to work, you must also have either LVS_EX_ONECLICKACTIVATE or LVS_EX_TWOCLICKACTIVATE turned on.

See Also Windows Common Controls and MFC Classes


Virtual List Controls

Home | Overview | Sample

A virtual list control is a list view control that has the LVS_OWNERDATA style. This style enables the control to support an item count up to a DWORD (the default item count only extends to an int). However, the biggest advantage provided by this style is the ability to only have a subset of data items in memory at any one time. This allows the virtual list view control to lend itself for use with large databases of information, where specific methods of accessing data are already in place.

Note In addition to providing virtual list functionality in CListCtrl, MFC also provides the same functionality in the CListView class.

There are some compatibility issues you should be aware of when developing virtual list controls. For more information, see Compatibility issues: styles, states, and messages in the Platform SDK.

Handling the LVN_GETDISPINFO Notification

Virtual list controls maintains very little item information. Except for the item selection and focus information, all item information is managed by the owner of the control. Information is requested by the framework via a LVN_GETDISPINFO notification message. To provide the requested information, the owner of the virtual list control (or the control itself) must handle this notification. This can easily be done using ClassWizard. The resultant code should look something like the following example (where CMyListCtrl is the virtual list control object and the control is handling the notification):

BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
   //{{AFX_MSG_MAP(CMyListCtrl)
   ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()

In the handler for the LVN_GETDISPINFO notification message, you must check to see what type of information is being requested. The possible values are:

  • LVIF_TEXT The pszText member must be filled in.

  • LVIF_IMAGE The iImage member must be filled in.

  • LVIF_INDENT The iIndent member must be filled in.

  • LVIF_PARAM The lParam member must be filled in.

  • LVIF_STATE The state member must be filled in.

You should then supply whatever information is requested back to the framework.

The following example (taken from the body of the notification handler for the list control object) demonstrates one possible method by supplying information for the text buffers and image of an item:

LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM* pItem= &(pDispInfo)->item;

int iItemIndx= pItem->iItem;

if (pItem->mask & LVIF_TEXT) //valid text buffer?
{
    switch(pItem->iSubItem){
        case 0: //fill in main text
            lstrcpy(pItem->pszText,
                m_Items[iItemIndx].m_strItemText);
            break;
        case 1: //fill in sub item 1 text
            lstrcpy(pItem->pszText,
                m_Items[iItemIndx].m_strSubItem1Text);
            break;
        case 2: //fill in sub item 2 text
            lstrcpy(pItem->pszText,
                m_Items[iItemIndx].m_strSubItem2Text);
            break;
    }
}

if pItem->mask & LVIF_IMAGE) //valid image?
        pItem->iImage=
            m_Items[iItemIndx].m_iImageIndex;

Caching and Virtual List Controls

Because this type of list control is intended for large data sets, it is recommended that you cache requested item data to improve retrieval performance. The framework provides a cache-hinting mechanism to assist in optimizing the cache by sending an LVN_ODCACHEHINT notification message. However, you must use a slightly different method to handle this notification. Using ClassWizard, override the OnChildNotify function of your list control object. In the case of this example, CMyListCtrl.

Inside the body of the handler, check for the LVN_ODCACHEHINT message and, if found, prepare your cache.

The following example (taken from the body of the OnChildNotify function) performs this check and calls the PrepCache member function of the CMyListCtrl class.

NMLVCACHEHINT* pcachehint=NULL;

if (message == WM_NOTIFY)
    {
        NMHDR* phdr = (NMHDR*)lParam;

        switch(phdr->code)
        {
        case LVN_ODCACHEHINT:
            pcachehint= (NMLVCACHEHINT*) phdr;
// Load the cache with the recommended range.
            PrepCache(pcachehint->iFrom, pcachehint->iTo);
            break;
        default:
            return CListCtrl::OnChildNotify(message, wParam, lParam, pLResult);
        }
        return FALSE;
    }
    else
        return CListCtrl::OnChildNotify(message, wParam, lParam, pLResult);

Notice that the notification is passed on to the base class (CListCtrl) if the message type is not LVN_ODCACHEHINT. For more information on preparing and maintaining a cache, see Cache Management in the Platform SDK.

Finding Specific Items

The LVN_ODFINDITEM notification message is sent by the virtual list control when a particular list control item needs to be found. The notification message is sent when the list view control receives quick key access or when it receives an LVM_FINDITEM message. Search information is sent in the form of an LVFINDINFO structure, which is a member of the NMLVFINDITEM structure. Handle this message by overriding the OnChildNotify function of your list control object and inside the body of the handler, check for the LVN_ODFINDITEM message. If found, perform the appropriate action.

You should be prepared to search for an item that matches the information given by the list view control. You should return the index of the item if successful, or -1 if no matching item is found.

See Also Windows Common Controls and MFC Classes


Destroying the List Control

Home | Overview | Sample

If you embed your CListCtrl object as a data member of a view or dialog class, it is destroyed when its owner is destroyed. If you use a CListView, the framework destroys the control when it destroys the view.

If you arrange for some of your list data to be stored in the application rather than the list control, you will need to arrange for its deallocation. For more information, see Callback Items and the Callback Mask in the Platform SDK.

In addition, you are responsible for deallocating any image lists you created and associated with the list control object.

See Also Windows Common Controls and MFC Classes


Using CMonthCalCtrl

Home | Overview | Sample

The month calendar control (CMonthCalCtrl)implements a calendar-like user interface. This provides the user with a very intuitive and recognizable method of entering or selecting a date. The control also provides the application with the means to obtain and set the date information in the control using existing data types. By default, the month calendar control displays the current day and month. However, the user is able to scroll to the previous and next months and select a specific month and/or year.

Note To use the CMonthCalCtrl class in your project, you must include AFXDTCTL.H, usually in STDAFX.H.

What do you want to know more about?

  • Creating the Month Calendar Control

  • Month Calendar Examples

  • Processing Notification Messages in Month Calendar Controls

  • Setting the Day State of a Month Calendar Control

See Also Windows Common Controls and MFC Classes


Creating the Month Calendar Control

Home | Overview | Sample

How the month calendar control is created depends on whether you are using the control in a dialog box or creating it in a nondialog window.

To use CMonthCalCtrl directly in a dialog box

  1. In the dialog editor, add a Month Calendar Control to your dialog template resource. Specify its control ID.

  2. Specify any styles required, using the Properties dialog box of the month calendar control.

  3. Use ClassWizard to add a member variable of type CMonthCalCtrl with the Control property. You can use this member to call CMonthCalCtrl member functions.

  4. Use ClassWizard to map handler functions in the dialog class for any month calendar control notification messages you need to handle.

  5. In OnInitDialog, set any additional styles for the CMonthCalCtrl object.

To use CMonthCalCtrl in a nondialog window

  1. Define the control in the view or window class.

  2. Call the control's Create member function, possibly in OnInitialUpdate, possibly as early as the parent window's OnCreate handler function (if you're subclassing the control). Set the styles for the control.

See Also Windows Common Controls and MFC Classes


Month Calendar Control Examples

Home | Overview | Sample

The CMNCTRL1 sample application demonstrates the various attributes of the CMonthCalCtrl class. The control, found on a separate tab in the sample, demonstrates basic functionality and allows the user to dynamically modify certain attributes.

See Also Windows Common Controls and MFC Classes


Processing Notification Messages in Month Calendar Controls

Home | Overview | Sample

As users interact with the month calendar control (selecting dates and/or viewing a different month), the control (CMonthCalCtrl) sends notification messages to its parent window, usually a view or dialog object. Handle these messages if you want to do something in response. For example, when the user selects a new month to view, you could provide a set of dates that should be emphasized.

Use WizardBar or ClassWizard to add notification handlers to the parent class for those messages you want to implement.

The following list describes the various notifications sent by the month calendar control.

  • MCN_GETDAYSTATE Requests information about which days should be displayed in bold. For information on handling this notification, see Setting the Day State of a Month Calendar Control.

  • MCN_SELCHANGE Notifies the parent that the selected date or range of the date has changed.

  • MCN_SELECT Notifies the parent that an explicit date selection has been made.

See Also Windows Common Controls and MFC Classes


Setting the Day State of a Month Calendar Control

Home | Overview | Sample

One of the attributes of a month calendar control is the ability to store information, referred to as the day state of the control, for each day of the month. This information is used to emphasize certain dates for the month currently displayed.

Note The CMonthCalCtrl object must have the MCS_DAYSTATE style to display day state information.

Day state information is expressed as a 32-bit data type, MONTHDAYSTATE. Each bit in a MONTHDAYSTATE bit field (1 through 31) represents the state of a day in a month. If a bit is on, the corresponding day will be displayed in bold; otherwise it will be displayed with no emphasis.

There are two methods for setting the day state of the month calendar control: explicitly with a call to CMonthCalCtrl::SetDayState or by handling the MCN_GETDAYSTATE notification message.

Handling the MCN_GETDAYSTATE Notification Message

The MCN_GETDAYSTATE message is sent by the control to determine how the days within the visible months should be displayed.

Note Because the control caches the previous and following months, in respect to the visible month, you will receive this notification every time a new month is chosen.

To properly handle this message, you must determine how many months day state information is being requested for, initialize an array of MONTHDAYSTATE structures with the proper values, and initialize the related structure member with the new information. The following procedure, detailing the necessary steps, assumes that you have a CMonthCalCtrl object called m_monthcal and an array of MONTHDAYSTATE objects, mdState.

To handle the MCN_GETDAYSTATE notification message

  1. Using ClassWizard, add a notification handler for the MCN_GETDAYSTATE message to the m_monthcal object.

  2. In the body of the handler, add the following code:
    NMDAYSTATE* pDayState= (NMDAYSTATE *)pNMHDR;

#define BOLDDAY(ds,iDay) if(iDay>0 && iDay<32)\
                            (ds)|=(0x00000001<<(iDay-1))
MONTHDAYSTATE mdState[3];
INT i, iMax;

    The example converts the pNMHDR pointer to the proper type and defines a helpful macro that sets specific bits in the MONTHDAYSTATE bitfield.

  3. After adding the previous code example, add the following code:
    iMax=pDayState->cDayState;

for(i=0;i<iMax;i++)
{
    mdState[i] = (MONTHDAYSTATE)0;
    BOLDDAY(mdState[i],15);
 }
pDayState->prgDayState = mdState;

    The example first determines how many months of information are being requested (pDayState->cDayState). For each month, the current bitfield (mdState) is initialized to zero and then the needed dates are set (in this case, the 15th of each month). Finally, the pDayState->prgDayState member is set, completing the MCN_DAYSTATE handler.

See Also Windows Common Controls and MFC Classes


Using CProgressCtrl

Home | Overview | Sample

You can use the progress control to indicate the progress of a lengthy operation. It is a rectangle that is gradually filled with the system highlight color as the operation progresses.

The progress control is represented in MFC by class CProgressCtrl.

When you initially create the progress control, you specify its size and position, parent window (usually a dialog box), and ID. By using the dwStyle parameter, you can also specify various window styles for the control and styles for how it fills.

What do you want to know more about?

  • Styles for the Progress Control

  • Settings for the Progress Control

  • Manipulating the Progress Control

See Also Windows Common Controls and MFC Classes


Styles for the Progress Control

Home | Overview | Sample

When you initially create the progress control (CProgressCtrl::Create), use the dwStyle parameter to specify the desired window styles for your progress control. The following list details the applicable window styles. The control ignores any window style other than the ones listed here. You should always create the control as a child window, usually of a dialog box parent.

Window Style | Effect
WS_BORDER | Creates a border around the window.
WS_CHILD | Creates a child window (should always be used for CProgressCtrl).
WS_CLIPCHILDREN | Excludes the area occupied by child windows when you draw within the parent window. Used when you create the parent window.
WS_CLIPSIBLINGS | Clips child windows relative to each other.
WS_DISABLED | Creates a window that is initially disabled.
WS_VISIBLE | Creates a window that is initially visible.
WS_TABSTOP | Specifies that the control can receive focus when the user presses the TAB key to move to it.

In addition, you can specify two styles that apply only to the progress control, PBS_VERTICAL and PBS_SMOOTH.

Use PBS_VERTICAL to orient the control vertically, rather than horizontally. Use PBS_SMOOTH to fill the control completely, rather than displaying small delineated squares that fill the control incrementally.

Without PBS_SMOOTH style:

With PBS_SMOOTH and PBS_VERTICAL styles:

For more information, see Window Styles in the Class Library Reference.


Settings for the Progress Control

Home | Overview | Sample

The basic settings for the progress control (CProgressCtrl) are the range and current position. The range represents the entire duration of the operation. The current position represents the progress that your application has made toward completing the operation. Any changes to the range or position cause the progress control to redraw itself.

By default, the range is set to 0 – 100, and the initial position is set to 0. To retrieve the current range settings for the progress control, use the GetRange member function. To change the range, use the SetRange member function.

To set the position, use SetPos. To retrieve the current position without specifying a new value, use GetPos. For example, you might want to simply query on the status of the current operation.

To step the current position of the progress control, use StepIt. To set the amount of each step, use SetStep

See Also Windows Common Controls and MFC Classes


Manipulating the Progress Control

Home | Overview | Sample

There are three ways to change the current position of a progress control (CProgressCtrl).

  • The position can be changed by a preset increment amount.

  • The position can be changed by an arbitrary amount.

  • The position can be changed to a specific value.

To change the position by a preset amount

  1. Use the SetStep member function to set the increment amount. By default, this value is 10. This value is typically set as one of the initial settings for the control. The step value can be negative.

  2. Use the StepIt member function to increment the position. This causes the control to redraw itself.

    Note StepIt will cause the position to wrap. For example, given a range of 1 – 100, a step of 20, and a position of 90, StepIt will set the position to 10.

To change the position by an arbitrary amount

  • Use the OffsetPos member function to change the position. OffsetPos will accept negative values.

    Note OffsetPos, unlike StepIt, will not wrap the position. The new position is adjusted to remain within the range.

To change the position to a specific value

  • Use the SetPos member function to set the position to a specific value. If necessary, the new position is adjusted to be within the range.

Typically, the progress control is used solely for output. To get the current position without specifying a new value, use GetPos.

See Also Windows Common Controls and MFC Classes


Using CReBarCtrl

Home | Overview | Sample

A rebar control acts as a container for child windows. These child windows, often other controls, are assigned to a rebar control band. A rebar control can contain one or more bands, with each band having any combination of a gripper bar, a bitmap, a text label, and a child window. However, bands cannot contain more than one child window.

The following illustration shows a rebar control that has two bands. One contains a gripper bar, a text label ("Address"), and a combo box child window. The other band contains a gripper bar, a text label, and a flat toolbar (implemented with a child window).

What do you want to know more about?

  • CReBar vs. CReBarCtrl

  • Creating a Rebar Control

  • Rebar Controls and Bands

  • Using an Image List with a Rebar Control

  • Using a Dialog Bar with a Rebar Control

  • Processing Notification Messages in a Rebar Control

See Also Windows Common Controls and MFC Classes


CReBar vs. CReBarCtrl

Home | Overview | Sample

MFC provides two classes to create rebars: CReBar and CReBarCtrl (which wraps the Windows common control API). CReBar provides all of the functionality of the rebar common control, and it handles many of the required common control settings and structures for you.

CReBarCtrl is a wrapper class for the Win32 rebar control, and therefore may be easier to implement if you do not intend to integrate the rebar into the MFC architecture. If you plan to use CReBarCtrl and integrate the rebar into the MFC architecture, you must take additional care to communicate rebar control manipulations to MFC. This communication is not difficult; however, it is additional work that is unneeded when you use CReBar.

Visual C++ provides two ways to take advantage of the rebar common control.

  • Create the rebar using CReBar, and then call CReBar::GetReBarCtrl to get access to the CReBarCtrl member functions.

    Note CReBar::GetReBarCtrl is an inline member function that casts the this pointer of the rebar object. This means that, at run time, the function call has no overhead.

  • Create the rebar using CReBarCtrl's constructor.

Either method will give you access to the member functions of the rebar control. When you call CReBar::GetReBarCtrl, it returns a reference to a CReBarCtrl object so you can use either set of member functions. See CReBar for information on constructing and creating a rebar using CReBar.

See Also Windows Common Controls and MFC Classes


Creating a Rebar Control

Home | Overview | Sample

CReBarCtrl objects should be created before the parent object is visible. This minimizes the possibilities of painting problems.

For instance, rebar controls (used in frame window objects) are commonly used as parent windows for toolbar controls. Therefore, the parent of the rebar control is the frame window object. Because the frame window object is the parent, the OnCreate member function (of the parent) is an excellent place to create the rebar control.

To use a CReBarCtrl object, you will typically follow these steps:

To use a CReBarCtrl object

  1. Construct the CReBarCtrl object.

  2. Call Create to create the Windows rebar common control and attach it to the CReBarCtrl object, specifying any desired styles.

  3. Load a bitmap, with a call to CBitmap::LoadBitmap, to be used as the background of the rebar control object.

  4. Create and initialize any child window objects (toolbars, dialog controls, and so on) that will be contained by the rebar control object.

  5. Initialize a REBARBANDINFO structure with the necessary information for the band about to be inserted.

  6. Call InsertBand to insert existing child windows (such as m_wndReToolBar) into the new rebar control. For more information on inserting bands into an existing rebar control, see Rebar Controls and Bands.

See Also Windows Common Controls and MFC Classes


Rebar Controls and Bands

Home | Overview | Sample

The main purpose of a rebar control is to act as a container for child windows, common dialog controls, menus, toolbars, and so on. This containment is supported by the concept of a "band." Each rebar band can contain any combination of a gripper bar, a bitmap, a text label, and a child window.

Class CReBarCtrl has many member functions that you can use to retrieve, and manipulate, information for a specific rebar band:

  • GetBandCount Retrieves the number of current bands in the rebar control.

  • GetBandInfo Initializes a REBARBANDINFO structure with information from the specified band. There is a corresponding SetBandInfo member function.

  • GetRect Retrieves the bounding rectangle of a specified band.

  • GetRowCount Retrieves the number of band rows in a rebar control.

  • IDToIndex Retrieves the index of a specified band.

  • GetBandBorders Retrieves the borders of a band.

In addition to manipulation, several member functions are provided that allow you to operate on specific rebar bands.

InsertBand and DeleteBand add and remove rebar bands. MinimizeBand and MaximizeBand affect the current size of a specific rebar band. MoveBand changes the index of a specific rebar band. ShowBand shows or hides a rebar band from the user.

The following example demonstrates adding a toolbar band (m_wndToolBar) to an existing rebar control (m_wndReBar). The band is described by initializing the rbi structure and then calling the InsertBand member function:

//load bitmap for toolbar background
m_bmap.LoadBitmap(IDB_BITMAP);

//create a toolbar band
m_wndToolBar.Create(this, TBSTYLE_TRANSPARENT | TBSTYLE_FLAT);
m_wndToolBar.LoadToolBar(IDR_MAINFRAME);

REBARBANDINFO rbi;
rbi.cbSize= sizeof(REBARBANDINFO);
rbi.fMask= RBBIM_BACKGROUND | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_TEXT;
rbi.fStyle= RBBS_GRIPPERALWAYS;
rbi.cxMinChild= 300;
rbi.cyMinChild= 30;
rbi.lpText= "Band #1";
rbi.cch= 7;
rbi.cx= 300;
rbi.hbmBack= (HBITMAP)m_bmap;
rbi.hwndChild= (HWND)m_wndToolBar;
m_wndReBar.InsertBand(-1, &rbi);

See Also Windows Common Controls and MFC Classes


Using an Image List with a Rebar Control

Home | Overview | Sample

Each rebar band can contain, among other things, an image from an associated image list. The following procedure details the necessary steps for displaying an image in a rebar band.

To display images in a rebar band

  1. Attach an image list to your rebar control object by making a call to SetImageList, passing a pointer to an existing image list.

  2. Modify the REBARBANDINFO structure to assign an image to a rebar band:
    • Set the fMask member to RBBIM_IMAGE, using the bitwise OR operator to include additional flags as necessary.

    • Set the iImage member to the image list index of the image to be displayed.
  3. Initialize any remaining data members, such as the size, text, and handle of the contained child window, with the necessary information.

  4. Insert the new band (with the image) with a call to CReBarCtrl::InsertBand, passing the REBARBANDINFO structure.

The following example assumes that an existing image list object with two images was attached to the rebar control object (m_wndReBar). A new rebar band (defined by rbi), containing the first image, is added with a call to InsertBand:

REBARBANDINFO rbi;
rbi.cbSize= sizeof(REBARBANDINFO);
rbi.fMask= RBBIM_BACKGROUND | RBBIM_CHILD | RBBIM_IMAGE | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_TEXT;
rbi.fStyle= RBBS_GRIPPERALWAYS;
rbi.cxMinChild= 200;
rbi.cyMinChild= 50;
rbi.lpText= "Band #1";
rbi.cch= 7;
rbi.cx= 300;
rbi.hbmBack= (HBITMAP)m_bmap3;
rbi.iImage= 0;
rbi.hwndChild= (HWND)m_wndToolBar;
BOOL bRes= m_wndReBar.InsertBand(-1, &rbi);

See Also Windows Common Controls and MFC Classes


Using a Dialog Bar with a Rebar Control

Home | Overview | Sample

As mentioned in Rebar Controls and Bands, each band can contain only one child window (or control). This might be a limitation if you want to have more than one child window per band. A convenient workaround is to create a dialog bar resource with multiple controls and then add a rebar band (containing the dialog bar) to the rebar control.

Normally, if you wanted the dialog bar band to appear transparent, you would set the WM_EX_TRANSPARENT extended style for the dialog bar object. However, because WM_EX_TRANSPARENT has some issues with properly painting the background of a dialog bar, you will need to do a little extra work to achieve the desired effect.

The following procedure details the steps necessary to achieve transparency without using the WM_EX_TRANSPARENT extended style.

To implement a transparent dialog bar in a rebar band

  1. Using ClassWizard, add a new class (for example, CMyDlgBar) that implements your dialog bar object.

  2. Add a handler for the WM_ERASEBKGND message.

  3. In the new handler, modify the existing code to match the following example:
    BOOL CMyDlgBar::OnEraseBkgnd( CDC* pDC )
{
    CWnd* pParent = GetParent();
    ASSERT_VALID(pParent);
    CPoint pt(0, 0);
    MapWindowPoints(pParent, &pt, 1);
    pt = pDC->OffsetWindowOrg(pt.x, pt.y);
    LRESULT lResult = pParent->SendMessage(WM_ERASEBKGND,
        (WPARAM)pDC->m_hDC, 0L);
    pDC->SetWindowOrg(pt.x, pt.y);
    return lResult;
}
  4. Add a handler for the WM_MOVE message.

  5. In the new handler, modify the existing code to match the following example:
    BOOL CMyDlgBar::OnMove( int cx, int cy )
{
    Invalidate();
}

The new handlers simulate the transparency of the dialog bar by forwarding the WM_ERASEBKGND message to the parent window and forcing a repaint every time the dialog bar object is moved.

See Also Windows Common Controls and MFC Classes


Processing Notification Messages in a Rebar Control

Home | Overview | Sample

In the parent class of the rebar control, create an OnChildNotify handler function with a switch statement for any rebar-control (CReBarCtrl) notification messages you want to handle. Notifications are sent to the parent window when the user drags objects over the rebar control, changes the layout of the rebar bands, deletes bands from the rebar control, and so on.

The following notification messages can be sent by the rebar control object:

  • RBN_AUTOSIZE Sent by a rebar control (created with the RBS_AUTOSIZE style) when the rebar automatically resizes itself.

  • RBN_BEGINDRAG Sent by a rebar control when the user begins dragging a band.

  • RBN_CHILDSIZE Sent by a rebar control when a band's child window is resized.

  • RBN_DELETEDBAND Sent by a rebar control after a band has been deleted.

  • RBN_DELETINGBAND Sent by a rebar control when a band is about to be deleted.

  • RBN_ENDDRAG Sent by a rebar control when the user stops dragging a band.

  • RBN_GETOBJECT Sent by a rebar control (created with the RBS_REGISTERDROP style) when an object is dragged over a band in the control.

  • RBN_HEIGHTCHANGE Sent by a rebar control when its height has changed.

  • RBN_LAYOUTCHANGED Sent by a rebar control when the user changes the layout of the control's bands.

For more information on these notifications, see the Rebar Control Messages section of the Platform SDK.

See Also Windows Common Controls and MFC Classes


Using CRichEditCtrl

Home | Overview | Sample

A rich edit control is a window in which the user can enter and edit text. The text can be assigned character and paragraph formatting, and can include embedded OLE objects. The rich edit control is represented in MFC by the CRichEditCtrl class.

What do you want to know more about?

  • Overview of the Rich Edit Control

  • Classes Related to Rich Edit Controls

  • Rich Edit Control Examples

  • Character Formatting in Rich Edit Controls

  • Paragraph Formatting in Rich Edit Controls

  • Current Selection in a Rich Edit Control

  • Word Breaks in a Rich Edit Control

  • Clipboard Operations in Rich Edit Controls

  • Stream Operations in Rich Edit Controls

  • Printing in Rich Edit Controls

  • Bottomless Rich Edit Controls

  • Notifications from a Rich Edit Control

See Also Windows Common Controls and MFC Classes


Overview of the Rich Edit Control

Home | Overview | Sample

Important If you are using a rich edit control in a dialog box (regardless of whether your application is SDI, MDI, or dialog-based), you must call AfxInitRichEdit once before the dialog box is displayed. A typical place to call this function is in your program's InitInstance member function. You do not need to call it for each time you display the dialog box, only the first time. You do not have to call AfxInitRichEdit if you are working with CRichEditView.

Rich edit controls (CRichEditCtrl) provide a programming interface for formatting text. However, an application must implement any user interface components necessary to make formatting operations available to the user. That is, the rich edit control supports changing the character or paragraph attributes of the selected text. Some examples of character attributes are bold, italics, font family, and point size. Examples of paragraph attributes include alignment, margins, and tab stops. However, it is up to you to provide the user interface, whether that is toolbar buttons, menu items, or a format character dialog box. There are also functions to query the rich edit control for the attributes of the current selection. Use these functions to display the current settings for the attributes, for example, setting a check mark on the command UI if the selection has the bold character formatting attribute.

For more information on character and paragraph formatting, see Character Formatting and Paragraph Formatting later in this article.

Rich edit controls support almost all of the operations and notification messages used with multiline edit controls. Thus, applications that already use edit controls can be easily changed to use rich edit controls. Additional messages and notifications enable applications to access the functionality unique to rich edit controls. For information about edit controls, see CEdit.

For more information on notifications, see Notifications from a Rich Edit Control later in this article.

See Also Windows Common Controls and MFC Classes


Classes Related to Rich Edit Controls

Home | Overview | Sample

The CRichEditView, CRichEditDoc, and CRichEditCntrItem classes provide the functionality of the rich edit control (CRichEditCtrl) within the context of MFC's document/view architecture. CRichEditView maintains the text and formatting characteristic of text. CRichEditDoc maintains the list of OLE client items that are in the view. CRichEditCntrItem provides container-side access to the OLE client item. To modify the contents of a CRichEditView, use CRichEditView::GetRichEditCtrl to access the underlying rich edit control.

See Also Windows Common Controls and MFC Classes


Rich Edit Control Examples

Home | Overview | Sample

The MFC OLE sample WORDPAD uses the CRichEditView, CRichEditDoc, and CRichEditCntrItem classes. By extension, it uses the CRichEditCtrl. For a quick description of these three classes, see Classes Related to Rich Edit Controls.

See Also Windows Common Controls and MFC Classes


Character Formatting in Rich Edit Controls

Home | Overview | Sample

You can use member functions of the rich edit control (CRichEditCtrl) to format characters and to retrieve formatting information. For characters, you can specify typeface, size, color, and effects such as bold, italic, and protected.

You can apply character formatting by using the SetSelectionCharFormat and SetWordCharFormat member functions. To determine the current character formatting for the selected text, use the GetSelectionCharFormat member function. The CHARFORMAT structure is used with these member functions to specify character attributes. One of the important members of CHARFORMAT is dwMask. In SetSelectionCharFormat and SetWordCharFormat, dwMask specifies which character attributes will be set by this function call. GetSelectionCharFormat reports the attributes of the first character in the selection; dwMask specifies the attributes that are consistent throughout the selection.

You can also get and set the "default character formatting," which is the formatting applied to any subsequently inserted characters. For example, if an application sets the default character formatting to bold and the user then types a character, that character is bold. To get and set default character formatting, use the GetDefaultCharFormat and SetDefaultCharFormat member functions.

The "protected" character attribute does not change the appearance of text. If the user attempts to modify protected text, a rich edit control sends its parent window an EN_PROTECTED notification message, allowing the parent window to allow or prevent the change. To receive this notification message, you must enable it by using the SetEventMask member function. For more information about the event mask, see Notifications from a Rich Edit Control, later in this article.

Foreground color is a character attribute, but background color is a property of the rich edit control. To set the background color, use the SetBackgroundColor member function.

See Also Windows Common Controls and MFC Classes


Paragraph Formatting in Rich Edit Controls

Home | Overview | Sample

You can use member functions of the rich edit control (CRichEditCtrl) to format paragraphs and to retrieve formatting information. Paragraph formatting attributes include alignment, tabs, indents, and numbering.

You can apply character formatting by using the SetParaFormat member function. To determine the current character formatting for the selected text, use the GetParaFormat member function. The PARAFORMAT structure is used with these member functions to specify character attributes. One of the important members of PARAFORMAT is dwMask. In SetParaFormat, dwMask specifies which paragraph attributes will be set by this function call. GetParaFormat reports the attributes of the first paragraph in the selection; dwMask specifies the attributes that are consistent throughout the selection.

See Also Windows Common Controls and MFC Classes


Current Selection in a Rich Edit Control

Home | Overview | Sample

The user can select text in a rich edit control (CRichEditCtrl) by using the mouse or the keyboard. The current selection is the range of selected characters, or the position of the insertion point if no characters are selected. An application can get information about the current selection, set the current selection, determine when the current selection changes, and show or hide the selection highlight.

To determine the current selection in a rich edit control, use the GetSel member function. To set the current selection, use the SetSel member function. The CHARRANGE structure is used with these functions to specify a range of characters. To retrieve information about the contents of the current selection, you can use the GetSelectionType member function.

By default, a rich edit control shows and hides the selection highlight when it gains and loses the focus. You can show or hide the selection highlight at any time by using the HideSelection member function. For example, an application might provide a Search dialog box to find text in a rich edit control. The application might select matching text without closing the dialog box, in which case it must use HideSelection to highlight the selection.

To get the selected text in a rich edit control, use the GetSelText member function. The text is copied to the specified character array. You must ensure that the array is large enough to hold the selected text plus a terminating null character.

You can search for a string in a rich edit control by using the FindText member function The FINDTEXTEX structure used with this function specifies the text range to search and the string to search for. You can also specify such options as whether the search is case-sensitive.

See Also Windows Common Controls and MFC Classes


Word Breaks in Rich Edit Controls

Home | Overview | Sample

A rich edit control (CRichEditCtrl) calls a function called a "word break procedure" to find breaks between words and to determine where it can break lines. The control uses this information when performing word-wrap operations and when processing the CTRL+LEFT and CTRL+RIGHT key combinations. An application can send messages to a rich edit control to replace the default word-break procedure, to retrieve word-break information, and to determine what line a given character falls on.

See Also Windows Common Controls and MFC Classes


Clipboard Operations in Rich Edit Controls

Home | Overview | Sample

Your application can paste the contents of the Clipboard into a rich edit control (CRichEditCtrl) using either the best available Clipboard format or a specific Clipboard format. You can also determine whether a rich edit control is capable of pasting a Clipboard format.

You can copy or cut the contents of the current selection by using the Copy or Cut member function. Similarly, you can paste the contents of the Clipboard into a rich edit control by using the Paste member function. The control pastes the first available format that it recognizes, which presumably is the most descriptive format.

To paste a specific Clipboard format, you can use the PasteSpecial member function. This function is useful for applications with a Paste Special command that enables the user to select the Clipboard format. You can use the CanPaste member function to determine whether a given format is recognized by the control.

You can also use CanPaste to determine whether any available Clipboard format is recognized by a rich edit control. This function is useful in the OnInitMenuPopup handler. An application might enable or gray its Paste command depending on whether the control can paste any available format.

Rich edit controls register two Clipboard formats: rich-text format and a format called RichEdit Text and Objects. An application can register these formats by using the RegisterClipboardFormat function, specifying the CF_RTF and CF_RETEXTOBJ values.

See Also Windows Common Controls and MFC Classes


Stream Operations in Rich Edit Controls

Home | Overview | Sample

You can use streams to transfer data into or out of a rich edit control (CRichEditCtrl). A stream is defined by an EDITSTREAM structure, which specifies a buffer and an application-defined callback function.

To read data into a rich edit control (that is, stream the data in), use the StreamIn member function. The control repeatedly calls the application-defined callback function, which transfers a portion of the data into the buffer each time.

To save the contents of a rich edit control (that is, stream the data out), you can use the StreamOut member function. The control repeatedly writes to the buffer and then calls the application-defined callback function. For each call, the callback function saves the contents of the buffer.

See Also Windows Common Controls and MFC Classes


Printing in Rich Edit Controls

Home | Overview | Sample

You can tell a rich edit control (CRichEditCtrl) to render its output for a specified device, such as a printer. You can also specify the output device for which a rich edit control formats its text.

To format part of the contents of a rich edit control for a specific device, you can use the FormatRange member function. The FORMATRANGE structure used with this function specifies the range of text to format as well as the device context (DC) for the target device.

After formatting text for an output device, you can send the output to the device by using the DisplayBand member function. By repeatedly using FormatRange and DisplayBand, an application that prints the contents of a rich edit control can implement banding. (Banding is division of output into smaller parts for printing purposes.)

You can use the SetTargetDevice member function to specify the target device for which a rich edit control formats its text. This function is useful for WYSIWYG (what you see is what you get) formatting, in which an application positions text using the default printer's font metrics instead of the screen's.

See Also Windows Common Controls and MFC Classes


Bottomless Rich Edit Controls

Home | Overview | Sample

Your application can resize a rich edit control (CRichEditCtrl) as needed so that it is always the same size as its contents. A rich edit control supports this so-called "bottomless" functionality by sending its parent window an EN_REQUESTRESIZE notification message whenever the size of its contents changes.

When processing the EN_REQUESTRESIZE notification message, an application should resize the control to the dimensions in the specified REQRESIZE structure. An application might also move any information near the control to accommodate the control's change in height. To resize the control, you can use the CWnd function SetWindowPos.

You can force a bottomless rich edit control to send an EN_REQUESTRESIZE notification message by using the RequestResize member function. This message can be useful in the OnSize handler.

To receive EN_REQUESTRESIZE notification messages, you must enable the notification by using the SetEventMask member function.

See Also Windows Common Controls and MFC Classes


Notifications from a Rich Edit Control

Home | Overview | Sample

Notification messages report events affecting a rich edit control (CRichEditCtrl). They can be processed by the parent window or, using message reflection, by the rich edit control itself. Rich edit controls support all of the notification messages used with edit controls as well as several additional ones. You can determine which notification messages a rich edit control sends its parent window by setting its "event mask."

To set the event mask for a rich edit control, use the SetEventMask member function. You can retrieve the current event mask for a rich edit control by using the GetEventMask member function.

The following paragraphs list several specific notifications and their uses:

  • EN_MSGFILTER Handling the EN_MSGFILTER notification lets a class, either the rich edit control or its parent window, filter all keyboard and mouse input to the control. The handler can prevent the keyboard or mouse message from being processed or can change the message by modifying the specified MSGFILTER structure.

  • EN_PROTECTED Handle the EN_PROTECTED notification message to detect when the user attempts to modify protected text. To mark a range of text as protected, you can set the protected character effect. For more information, see Character Formatting in Rich Edit Controls.

  • EN_DROPFILES You can enable the user to drop files in a rich edit control by processing the EN_DROPFILES notification message. The specified ENDROPFILES structure contains information about the files being dropped.

  • EN_SELCHANGE An application can detect when the current selection changes by processing the EN_SELCHANGE notification message. The notification message specifies a SELCHANGE structure containing information about the new selection.

See Also Windows Common Controls and MFC Classes


Using CSliderCtrl

Home | Overview | Sample

The CSliderCtrl class represents a slider control, which is also called a trackbar. A "slider control" is a window that contains a slider and optional tick marks. When the user moves the slider, using either the mouse or the arrow keys, the slider control sends notification messages to indicate the change.

Slider controls are useful when you want the user to select a discrete value or a set of consecutive values in a range. For example, you might use a slider control to allow the user to set the repeat rate of the keyboard by moving the slider to a given tick mark.

The slider in a slider control moves in increments that you specify when you create it. For example, if you specify that the slider control should have a range of five, the slider can only occupy six positions: a position at the left side of the slider control and one position for each increment in the range. Typically, each of these positions is identified by a tick mark.

What do you want to know more about?

  • Using Slider Controls

  • Slider Control Styles

  • Slider Control Member Functions

  • Slider Notification Messages

See Also Windows Common Controls and MFC Classes


Using Slider Controls

Home | Overview | Sample

Typical usage of an slider control follows the pattern below:

  • The control is created. If the control is specified in a dialog box template, creation is automatic when the dialog box is created. (You should have a CSliderCtrl member in your dialog class that corresponds to the slider control.) Alternatively, you can use the Create member function to create the control as a child window of any window.

  • Call the various Set member functions to set values for the control. Changes that you can make include setting the minimum and maximum positions for the slider, drawing tick marks, setting a selection range, and repositioning the slider. For controls in a dialog box, a good time to do this is in the dialog's OnInitDialog function.

  • As the user interacts with the control, it will send various notification messages. You can extract the slider value from the control by calling the GetPos member function.

  • When you're done with the control, you need to make sure it's properly destroyed. If the slider control is in a dialog box, it and the CSliderCtrl object will be destroyed automatically. If not, you need to ensure that both the control and the CSliderCtrl object are properly destroyed.

See Also Windows Common Controls and MFC Classes


Slider Control Styles

Home | Overview | Sample

Slider controls (CSliderCtrl) can have either a vertical or horizontal orientation. They can have tick marks on either side, both sides, or neither. They can also be used to specify a range of consecutive values. These properties are controlled by using slider control styles, which you specify when you create the slider control.

The TBS_HORZ and TBS_VERT styles determine the orientation of the slider control. If you do not specify an orientation, the slider control is oriented horizontally.

The TBS_AUTOTICKS style creates a slider control that has a tick mark for each increment in its range of values. These tick marks are added automatically when you call the SetRange member function. If you do not specify TBS_AUTOTICKS, you can use member functions, such as SetTic and SetTicFreq, to specify the positions of the tick marks. To create a slider control that does not display tick marks, you can use the TBS_NOTICKS style.

You can display tick marks on either or both sides of the slider control. For horizontal slider controls, you can specify the TBS_BOTTOM or TBS_TOP style. For vertical slider controls, you can specify the TBS_RIGHT or TBS_LEFT style. (TBS_BOTTOM and TBS_RIGHT are the default settings.) For tick marks on both sides of the slider control in any orientation, specify the TBS_BOTH style.

A slider control can display a selection range only if you specify the TBS_ENABLESELRANGE style when you create it. When a slider control has this style, the tick marks at the starting and ending positions of a selection range are displayed as triangles (instead of vertical dashes) and the selection range is highlighted. For example, selection ranges might be useful in a simple scheduling application. The user could select a range of tick marks corresponding to hours in a day to identify a scheduled meeting time.

By default, the length of a slider control's slider varies as the selection range changes. If the slider control has the TBS_FIXEDLENGTH style, the length of the slider remains the same even if the selection range changes. A slider control that has the TBS_NOTHUMB style does not include a slider.

See Also Windows Common Controls and MFC Classes


Slider Control Member Functions

Home | Overview | Sample

An application can call the slider control's member functions to retrieve information about the slider control (CSliderCtrl) and to change its characteristics.

To retrieve the position of the slider (that is, the value the user has chosen), use the GetPos member function. To set the position of the slider, use the SetPos member function. At any time you can use the VerifyPos member function to make sure that the slider is between the minimum and maximum values.

The range of a slider control is the set of contiguous values that the slider control can represent. Most applications use the SetRange member function to set the range of a slider control when it is first created. Applications can dynamically alter the range after the slider control has been created by using the SetRangeMax and SetRangeMin member functions. An application that allows the range to be changed dynamically typically retrieves the final range settings when the user has finished working with the slider control. To retrieve these settings, use the GetRange, GetRangeMax, and GetRangeMin member functions.

An application can use the TBS_AUTOTICKS style to have a slider control's tick marks displayed automatically. If an application needs to control the position or frequency of the tick marks, however, a number of member functions can be used.

To set the position of a tick mark, an application can use the SetTic member function. The SetTicFreq member function allows an application to set tick marks that appear at regular intervals in the slider control's range. For example, the application can use this member function to display only 10 tick marks in a range of 1 through 100.

To retrieve the index in the range corresponding to a tick mark, use the GetTic member function. The GetTicArray member function retrieves an array of these indices. To retrieve the position of a tick mark, in client coordinates, use the GetTicPos member function. An application can retrieve the number of tick marks by using the GetNumTics member function.

The ClearTics member function removes all of a slider control's tick marks.

A slider control's line size determines how far the slider moves when an application receives a TB_LINEDOWN or TB_LINEUP notification message. Similarly, the page size determines the response to the TB_PAGEDOWN and TB_PAGEUP notification messages. Applications can retrieve and set the line and page size values by using the GetLineSize, SetLineSize, GetPageSize, and SetPageSize member functions.

An application can use member functions to retrieve the dimensions of a slider control. The GetThumbRect member function retrieves the bounding rectangle for the slider. The GetChannelRect member function retrieves the bounding rectangle for the slider control's channel. (The channel is the area over which the slider moves and which contains the highlight when a range is selected.)

If a slider control has the TBS_ENABLESELRANGE style, the user can select a range of contiguous values from it. A number of member functions allow the selection range to be adjusted dynamically. The SetSelection member function sets the starting and ending positions of a selection. When the user has finished setting a selection range, an application can retrieve the settings by using the GetSelection member function. To clear a user's selection, use the ClearSel member function.

See Also Windows Common Controls and MFC Classes


Slider Notification Messages

Home | Overview | Sample

A slider control notifies its parent window of user actions by sending the parent WM_HSCROLL messages. You can override the parent's OnHScroll member function to handle these messages. This function will be passed a notification code, the position of the slider, and a pointer to the CSliderCtrl object. Note that the pointer is of type CScrollBar * even though it points to a CSliderCtrl object. You may need to typecast this pointer if you need to manipulate the slider control.

Rather than using the scroll bar notification codes, slider controls send a different set of notification codes. A slider control sends the TB_BOTTOM, TB_LINEDOWN, TB_LINEUP, and TB_TOP notification codes only when the user interacts with a slider control by using the keyboard. The TB_THUMBPOSITION and TB_THUMBTRACK notification messages are only sent when the user is using the mouse. The TB_ENDTRACK, TB_PAGEDOWN, and TB_PAGEUP notification codes are sent in both cases.

The following table lists the slider control notification messages and the events (virtual-key codes or mouse events) that cause the notifications to be sent.

Notification message | Event causing notification to be sent
TB_BOTTOM | VK_END
TB_ENDTRACK | WM_KEYUP (the user released a key that sent a relevant virtual-key code)
TB_LINEDOWN | VK_RIGHT or VK_DOWN
TB_LINEUP | VK_LEFT or VK_UP
TB_PAGEDOWN | VK_NEXT (the user clicked the channel below or to the right of the slider)
TB_PAGEUP | VK_PRIOR (the user clicked the channel above or to the left of the slider)
TB_THUMBPOSITION | WM_LBUTTONUP following a TB_THUMBTRACK notification message
TB_THUMBTRACK | Slider movement (the user dragged the slider)
TB_TOP | VK_HOME

See Also Windows Common Controls and MFC Classes


Using CSpinButtonCtrl

Home | Overview | Sample

The spin button control (also called an up-down control) provides a pair of arrows that the user can click to adjust a value. This value is called the current position. The position stays within the range of the spin button. When the user clicks the up arrow, the position moves toward the maximum; and when the user clicks the down arrow, the position moves toward the minimum.

The spin button control is represented in MFC by class CSpinButtonCtrl.

Note The default range for the spin button has the maximum set to zero (0) and the minimum set to 100. Since the maximum value is less than the minimum value, clicking the up arrow will decrease the position and clicking the down arrow will increase it. Use CSpinButtonCtrl::SetRange to adjust these values.

Typically, the current position is displayed in a companion control. The companion control is called the "buddy window." For an illustration of a spin button control, see About Up-Down Controls in the Platform SDK.

What do you want to know more about?

  • Spin Button Styles

  • Spin Button Member Functions

See Also Windows Common Controls and MFC Classes


Spin Button Styles

Home | Overview | Sample

Many of the settings for a spin button (CSpinButtonCtrl) are controlled by styles. You can set the following styles using the Styles tab of the Spin Properties dialog box in the dialog editor.

  • Orientation Either Vertical or Horizontal. Controls the orientation of the arrow buttons. Associated with the UDS_HORZ style.

  • Alignment One of Unattached, Left, or Right. Controls the location of the spin button. Left and Right position the spin button next to the buddy window. The width of the buddy window is decreased to accommodate the spin button. Associated with the UDS_ALIGNLEFT and UDS_ALIGNRIGHT styles.

  • Auto Buddy Automatically selects the previous window in Z-order as buddy window to the spin button. In a dialog template, this is the control which precedes the spin button in the tab order. Associated with the UDS_AUTOBUDDY style.

  • Set Buddy Integer Causes the spin control to increment and decrement the caption of the buddy window as the current position changes. Associated with the UDS_SETBUDDYINT style.

  • No Thousands Does not insert the thousands separator in the value in the caption of the buddy window. Associated with the UDS_NOTHOUSANDS style.

    Note Set this style if you want to use dialog data exchange (DDX) to get the integer value from the buddy control. DDX_Text does not accept embedded thousand separators.

  • Wrap Causes the position to "wrap" as the value is incremented or decremented beyond the range of the control. Associated with the UDS_WRAP style.

  • Arrow Keys Causes the spin button to increment or decrement the position when the UP ARROW and DOWN ARROW keys are pressed. Associated with the UDS_ARROWKEYS style.

See Also Windows Common Controls and MFC Classes


Spin Button Member Functions

Home | Overview | Sample

There are several member functions available for the spin control (CSpinButtonCtrl). Use these functions to change the following attributes of the spin button.

  • Acceleration You can adjust the rate at which the position changes when the user holds down the arrow button. To work with acceleration, use the SetAccel and GetAccel member functions.

  • Base You can change the base (either 10 or 16) used to display the position in the caption of the buddy window. To work with the base, use the GetBase and SetBase member functions.

  • Buddy Window You can dynamically set the buddy window. To query or change which control is the buddy window, use the GetBuddy and SetBuddy member functions.

  • Position You can query and change the position. To work directly with position, use the GetPos and SetPos member functions. Since the caption of the buddy control may have changed (for example, in the case that the buddy is an edit control), GetPos retrieves the current caption and adjusts the position accordingly.

  • Range You can change the maximum and minimum positions for the spin button. By default, the maximum is set to 0, and the minimum is set to 100. Since the default maximum is less than the default minimum, the actions of the arrow buttons is counter-intuitive. Typically, you will set the range using the SetRange member function. To query the range use GetRange.

See Also Windows Common Controls and MFC Classes


Using CStatusBarCtrl

Home | Overview | Sample

You can use the status bar control (CStatusBarCtrl) to create a control window that reflects various kinds of status information about the application. The status window can be divided into parts that display more than one type of information.

What do you want to know more about?

  • Methods of Creating a Status Bar

  • Settings for the CStatusBarCtrl

  • Using CStatusBarCtrl to Create a CStatusBarCtrl Object

  • Setting the Mode of a CStatusBarCtrl Object

  • Initializing the Parts of a CStatusBarCtrl Object

  • Using Tooltips in a CStatusBarCtrl Object

See Also Windows Common Controls and MFC Classes


Methods of Creating a Status Bar

Home | Overview | Sample

MFC provides two classes to create status bars: CStatusBar and CStatusBarCtrl (which wraps the Windows common control API). CStatusBar provides all of the functionality of the status bar common control, it automatically interacts with menus and toolbars, and it handles many of the required common control settings and structures for you; however, your resulting executable usually will be larger than that created by using CStatusBarCtrl.

CStatusBarCtrl usually results in a smaller executable, and you may prefer to use CStatusBarCtrl if you do not intend to integrate the status bar into the MFC architecture. If you plan to use CStatusBarCtrl and integrate the status bar into the MFC architecture, you must take additional care to communicate status bar control manipulations to MFC. This communication is not difficult; however, it is additional work that is unneeded when you use CStatusBar.

Visual C++ provides two ways to take advantage of the status bar common control.

  • Create the status bar using CStatusBar, and then call CStatusBar::GetStatusBarCtrl to get access to the CStatusBarCtrl member functions.

  • Create the status bar using CStatusBarCtrl's constructor.

Either method will give you access to the member functions of the status bar control. When you call CStatusBar::GetStatusBarCtrl, it returns a reference to a CStatusBarCtrl object so you can use either set of member functions. See CStatusBar for information on constructing and creating a status bar using CStatusBar.

See Also Windows Common Controls and MFC Classes


Settings for the CStatusBarCtrl

Home | Overview | Sample

The default position of a CStatusBarCtrl status window is along the bottom of the parent window, but you can specify the CCS_TOP style to have it appear at the top of the parent window's client area.

You can specify the SBARS_SIZEGRIP style to include a sizing grip at the right end of the CStatusBarCtrl status window. A sizing grip is similar to a sizing border; it is a rectangular area that the user can click and drag to resize the parent window.

Note If you combine the CCS_TOP and SBARS_SIZEGRIP styles, the resulting sizing grip is not functional even though the system draws it in the status window.

The window procedure for the status window automatically sets the initial size and position of the control window. The width is the same as that of the parent window's client area. The height is based on the metrics of the font that is currently selected into the status window's device context and on the width of the window's borders.

The window procedure automatically adjusts the size of the status window whenever it receives a WM_SIZE message. Typically, when the size of the parent window changes, the parent sends a WM_SIZE message to the status window.

You can set the minimum height of a status window's drawing area by calling SetMinHeight, specifying the minimum height in pixels. The drawing area does not include the window's borders.

You retrieve the widths of the borders of a status window by calling GetBorders. This member function includes the pointer to a three-element array that receives the width of the horizontal border, the vertical border, and the border between rectangles.

See Also Windows Common Controls and MFC Classes


Using CStatusBarCtrl to Create a CStatusBarCtrl Object

Home | Overview | Sample

Here is an example of a typical use of CStatusBarCtrl:

To use a status bar control with parts

  1. Construct the CStatusBarCtrl object.

  2. Call SetMinHeight if you want to set the minimum height of the status bar control's drawing area.

  3. Call SetBkColor to set the background color of the status bar control.

  4. Call SetParts to set the number of parts in a status bar control and the coordinate of the right edge of each part.

  5. Call SetText to set the text in a given part of the status bar control. The message invalidates the portion of the control that has changed, causing it to display the new text when the control next receives the WM_PAINT message.

In some cases, the status bar only needs to display a line of text. In this case, make a call to SetSimple. This puts the status bar control into "simple" mode, which displays a single line of text.

See Also Windows Common Controls and MFC Classes


Setting the Mode of a CStatusBarCtrl Object

Home | Overview | Sample

There are two modes for a CStatusBarCtrl object: simple and nonsimple. In the majority of cases, your status bar control will have one or more parts, along with text and perhaps an icon or icons. This is called the nonsimple mode. For more information on this mode, see Initializing the Parts of a CStatusBarCtrl Object.

However, there are cases where you only need to display a single line of text. In this case, the simple mode is sufficient for your needs. To change the mode of the CStatusBarCtrl object to simple, make a call to the SetSimple member function. Once the status bar control is in simple mode, set the text by calling the SetText member function, passing 255 as the value for the nPane parameter.

You can use the IsSimple function to determine what mode the CStatusBarCtrl object is in.

Note If the status bar object is being changed from nonsimple to simple, or vice versa, the window is immediately redrawn and, if applicable, any defined parts are automatically restored.

See Also Windows Common Controls and MFC Classes


Initializing the Parts of a CStatusBarCtrl Object

Home | Overview | Sample

By default, a status bar displays status information using separate panes. These panes (also referred to as parts) can contain either a text string, an icon, or both.

Use SetParts to define how many parts, and the length, the status bar will have. After you have created the parts of the status bar, make calls to SetText and SetIcon to set the text or icon for a specific part of the status bar. Once the part has been successfully set, the control is automatically redrawn.

The following example initializes an existing CStatusBarCtrl object (m_pStatBarCtrl) with four panes and then sets an icon (IDR_LIGHT1) and some text (IDC_PART1_STR) in the second part.

int strPartDim[4]= {80, 160, 240, -1};
CMyApp* pApp= (CMyApp*) AfxGetApp();

m_icon1= pApp->LoadIcon(IDR_LIGHT1);

m_pStatBarCtrl->SetParts(4, strPartDim);
m_pStatBarCtrl->SetIcon(1, m_icon1);
m_pStatBarCtrl->SetText(IDC_PART1_STR, 1, 0);

For more information on setting the mode of a CStatusBarCtrl object to simple, see Setting the Mode of a CStatusBarCtrl Object.

See Also Windows Common Controls and MFC Classes


Using Tooltips in a CStatusBarCtrl Object

Home | Overview | Sample

To enable tooltips for a status bar control, create the CStatusBarCtrl object with the SBT_TOOLTIPS style.

Note If you are using a CStatusBar object to implement your status bar, use the CStatusBar::CreateEx function. It allows you to specify additional styles for the embedded CStatusBarCtrl object.

Once the CStatusBarCtrl object has been successfully created, use CStatusBarCtrl::SetTipText and CStatusBarCtrl::GetTipText to set and retrieve the tip text for a specific pane.

Once the tooltip has been set, it is displayed only if the part has an icon and no text, or if all of the text cannot be displayed inside the part. Tooltips are not supported in simple mode.

See Also Windows Common Controls and MFC Classes


Using CTabCtrl

Home | Overview | Sample

A "tab control" is analogous to the dividers in a notebook or the labeled folders in a file cabinet. Use the tab control, represented by class CTabCtrl, to show multiple pages of information or controls to a user, one at a time, in a format that suggests a peer or logical relationship between each page.

For more information on tab controls, see Tab Controls in the Platform SDK.

What do you want to know more about?

  • Tab Controls and Property Sheets

  • Tab Control Examples

  • Tabs and Tab Control Attributes

  • Making Owner-Drawn Tabs

  • Working with a Tab Control

  • Creating the Tab Control

  • Adding Tabs to a Tab Control

  • Processing Tab Control Notification Messages

See Also Windows Common Controls and MFC Classes


Tab Controls and Property Sheets

Home | Overview | Sample

The most common use of the tab control (CTabCtrl) is in conjunction with a property sheet. Property sheets are multiple-page dialogs or "tab dialogs" that can display up to 24 dialog template resources to the user. For examples of property sheets, see the Display Properties dialog box in Windows 95 or the following MFC sample application:

CMNCTRL1: Demonstrates Common Control Classes, Part 1

CMNCTRL2: Demonstrates Common Control Classes, Part 2

Property sheets can be easily implemented using the MFC class CPropertySheet.

See Also Windows Common Controls and MFC Classes


Tab Control Examples

Home | Overview | Sample

Use of CTabCtrl is illustrated in the following MFC sample application:

FIRE: Demonstrates Windows 95 Common Controls

See Also Windows Common Controls and MFC Classes


Tabs and Tab Control Attributes

Home | Overview | Sample

You have considerable control over the appearance and behavior of tabs that make up a tab control (CTabCtrl). Each tab can have a label, an icon, an item state, and an application-defined 32-bit value associated with it. For each tab, you can display the icon, the label, or both.

In addition, each tab item can have three possible states: pressed, unpressed, or highlighted. This state can only be set by modifying an existing tab item. To modify an existing tab item, retrieve it with a call to GetItem, modify the TCITEM structure (specifically the dwState and dwStateMask data members), and then return the modified TCITEM structure with a call to SetItem. If you need to clear the item states of all the tab items in a CTabCtrl object, make a call to DeselectAll. This function resets the state of all tab items or all items except the one currently selected.

The following code clears the state of all tab items and then modifies the state of the third item:

//modify the third item to be highlighted
TCITEM curItem;

m_tabCtrl.DeselectAll(FALSE); //reset all tab items
curItem.mask= TCIF_STATE;
m_tabCtrl.GetItem(2, &curItem);
curItem.mask= TCIF_STATE;
curItem.dwState= TCIS_HIGHLIGHTED;
curItem.dwStateMask= TCIS_HIGHLIGHTED;
m_tabCtrl.SetItem(2, &curItem);

For more information about tab attributes, see Tabs and Tab Attributes in the Platform SDK. For more information about adding tabs to a tab control, see Adding Tabs to a Tab Control later in this article.

See Also Windows Common Controls and MFC Classes


Making Owner-Drawn Tabs

Home | Overview | Sample

You can define individual items of a tab control (CTabCtrl) to be owner-drawn items. For more information, see Owner-Drawn Tabs in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Working with a Tab Control

Home | Overview | Sample

The easiest way to use a tab control (CTabCtrl) is by adding it to a dialog template resource with the dialog editor. You can also use a tab control by itself. MFC calls InitCommonControls for you. The key tasks are as follows:

  • Creating the tab control

  • Adding tabs to a tab control

  • Processing tab control notification messages

If the tab control object is embedded in a parent view or dialog class, the control is destroyed when the parent is destroyed.

See Also Windows Common Controls and MFC Classes


Creating the Tab Control

Home | Overview | Sample

How the tab control is created depends on whether you are using the control in a dialog box or creating it in a nondialog window.

To use CTabCtrl directly in a dialog box

  1. In the dialog editor, add a Tab Control to your dialog template resource. Specify its control ID.

  2. Use ClassWizard to add a member variable of type CTabCtrl with the Control property. You can use this member to call CTabCtrl member functions.

  3. Use ClassWizard to map handler functions in the dialog class for any tab control notification messages you need to handle.

  4. In OnInitDialog, set the styles for the CTabCtrl.

To use CTabCtrl in a nondialog window

  1. Define the control in the view or window class.

  2. Call the control's Create member function, possibly in OnInitialUpdate, possibly as early as the parent window's OnCreate handler function (if you're subclassing the control). Set the styles for the control.

After the CTabCtrl object has been created, you can set or clear the following extended styles:

  • TCS_EX_FLATSEPARATORS The tab control will draw separators between the tab items. This extended style only affects tab controls that have the TCS_BUTTONS and TCS_FLATBUTTONS styles. By default, creating the tab control with the TCS_FLATBUTTONS style sets this extended style.

  • TCS_EX_REGISTERDROP The tab control generates TCN_GETOBJECT notification messages to request a drop target object when an object is dragged over the tab items in the control.

    Note To receive the TCN_GETOBJECT notification, you must initialize the OLE libraries with a call to AfxOleInit.

These styles can be retrieved and set, after the control has been created, with respective calls to the GetExtendedStyle and SetExtendedStyle member functions.

For instance, set the TCS_EX_FLATSEPARATORS style with the following lines of code:

DWORD dwExStyle= m_tabCtrl.GetExtendedStyle();
m_tabCtrl.SetExtendedStyle(dwExStyle | TCS_EX_FLATSEPARATORS);

Clear the TCS_EX_FLATSEPARATORS style from a CTabCtrl object with the following lines of code:

DWORD dwExStyle= m_tabCtrl.GetExtendedStyle();
m_tabCtrl.SetExtendedStyle(dwExStyle & ~TCS_EX_FLATSEPARATORS);

This will remove the separators that appear between the buttons of your CTabCtrl object.

See Also Windows Common Controls and MFC Classes


Adding Tabs to a Tab Control

Home | Overview | Sample

After creating the tab control (CTabCtrl), add as many tabs as you need.

To add a tab item

  1. Prepare a TCITEM structure.

  2. Call CTabCtrl::InsertItem, passing the structure.

  3. Repeat steps 1 and 2 for additional tab items.

For more information, see Creating a Tab Control in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Processing Tab Control Notification Messages

Home | Overview | Sample

As users click tabs or buttons, the tab control (CTabCtrl) sends notification messages to its parent window. Handle these messages if you want to do something in response. For example, when the user clicks a tab, you may want to preset control data on the page prior to displaying it.

Process WM_NOTIFY messages from the tab control in your view or dialog class. Use WizardBar or ClassWizard to create an OnChildNotify handler function with a switch statement based on which notification message is being handled. For a list of the notifications a tab control can send to its parent window, see Tab Control Notification Messages in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Using CToolBarCtrl

Home | Overview | Sample

You can use the toolbar control (CToolBarCtrl) to create a control window containing buttons and optional spaces. Each button in the toolbar control window sends a command message to the parent window as the user chooses it. Typically, the buttons in a toolbar correspond to items in the application's menu, providing an additional and more direct way for the user to access an application's commands.

What do you want to know more about?

  • Methods of Creating a Toolbar

  • Settings for the Toolbar Control

  • Creating a CToolBarCtrl Object

  • Using Image Lists in a Toolbar Control

  • Using Drop-Down Buttons in a Toolbar Control

  • Customizing the Appearance of a Toolbar Control

See Also Windows Common Controls and MFC Classes


Methods of Creating a Toolbar

Home | Overview | Sample

MFC provides two classes to create toolbars: CToolBar and CToolBarCtrl (which wraps the Windows common control API). CToolBar provides all of the functionality of the toolbar common control, and it handles many of the required common control settings and structures for you; however, your resulting executable usually will be larger than that created by using CToolBarCtrl.

CToolBarCtrl usually results in a smaller executable, and you may prefer to use CToolBarCtrl if you do not intend to integrate the toolbar into the MFC architecture. If you plan to use CToolBarCtrl and integrate the toolbar into the MFC architecture, you must take additional care to communicate toolbar control manipulations to MFC. This communication is not difficult; however, it is additional work that is unneeded when you use CToolBar.

Visual C++ provides two ways to take advantage of the toolbar common control.

  • Create the toolbar using CToolBar, and then call CToolBar::GetToolBarCtrl to get access to the CToolBarCtrl member functions.

  • Create the toolbar using CToolBarCtrl's constructor.

Either method will give you access to the member functions of the toolbar control. When you call CToolBar::GetToolBarCtrl, it returns a reference to a CToolBarCtrl object so you can use either set of member functions. See CToolBar for information on constructing and creating a toolbar using CToolBar.

See Also Windows Common Controls and MFC Classes


Settings for the Toolbar Control

Home | Overview | Sample

The buttons on a toolbar can display a bitmap, a string, or both. By default, the image size is set to the dimensions of 16 by 15 pixels. All buttons are the same width, by default 24 by 22 pixels. A toolbar's height is determined by the height of the buttons, and a toolbar's width is the same as the width of the parent window's client area, also by default.

A toolbar can have built-in customization features, including a system-defined customization dialog box, that allow the user to insert, delete, or rearrange toolbar buttons. An application determines whether the customization features are available to the user and controls the extent to which the user can customize the toolbar. For more information about customizing the toolbar, see CToolBarCtrl: Handling Customization Notifications and class CToolBarCtrl in the Class Library Reference.

See Also Windows Common Controls and MFC Classes


Creating a CToolBarCtrl Object

Home | Overview | Sample

CToolBarCtrl objects contain several internal data structures — a list of button image bitmaps, a list of button label stings, and a list of TBBUTTON structures — that associate an image and/or string with the position, style, state, and command ID of the button. Each of the elements of these data structures is referred to by a zero-based index. Before you can use a CToolBarCtrl object, you must set up these data structures. For a list of the data structures, see Toolbar Controls in the Platform SDK. The list of strings can only be used for button labels; you cannot retrieve strings from the toolbar.

To use a CToolBarCtrl object, you will typically follow these steps:

To use a CToolBarCtrl object

  1. Construct the CToolBarCtrl object.

  2. Call Create to create the Windows toolbar common control and attach it to the CToolBarCtrl object. If you want bitmap images for buttons, add the button bitmaps to the toolbar by calling AddBitmap. If you want string labels for buttons, add the strings to the toolbar by calling AddString and/or AddStrings.

  3. Add button structures to the toolbar by calling AddButtons.

  4. If you want tool tips, handle TTN_NEEDTEXT messages in the toolbar's owner window as described in CToolBarCtrl: Handling Tool Tip Notifications in the Class Library Reference.

  5. If you want your user to be able to customize the toolbar, handle customization notification messages in the owner window as described in CToolBarCtrl: Handling Customization Notifications in the Class Library Reference.

See Also Windows Common Controls and MFC Classes


Using Image Lists in a Toolbar Control

Home | Overview | Sample

By default, the images used by the buttons in a toolbar control are stored as a single bitmap. However, you can also store button images in a set of image lists. The toolbar control object can use up to three separate image lists:

  • Enabled image list Contains images for toolbar buttons that are currently enabled.

  • Disabled image list Contains images for toolbar buttons that are currently disabled.

  • Highlighted image list Contains images for toolbar buttons that are currently highlighted. This image list is used only when the toolbar uses the TBSTYLE_FLAT style.

These image lists are used by the toolbar control when you associate them with the CToolBarCtrl object. This association is accomplished by making calls to CToolBarCtrl::SetImageList, SetDisabledImageList, and SetHotImageList.

By default, MFC uses the CToolBar class to implement MFC application toolbars. However, the GetToolBarCtrl member function can be used to retrieve the embedded CToolBarCtrl object. You can then make calls to CToolBarCtrl member functions using the returned object.

The following example demonstrates this technique by assigning an enabled (m_TBarImages) and disabled (m_TBarDis) image list to a CToolBarCtrl object (m_wndToolBar).

CWinApp* pApp= AfxGetApp();

m_TBarImages.Create(16, 16, ILC_COLOR, 4, 4);
m_TBarImages.Add(pApp->LoadIcon(IDI_BLK));
m_TBarImages.Add(pApp->LoadIcon(IDI_RED));
m_TBarImages.Add(pApp->LoadIcon(IDI_YELL));
m_TBarImages.Add(pApp->LoadIcon(IDI_WHI));

m_TBarDis.Create(16, 16, ILC_COLOR, 4, 4);
m_TBarDis.Add(pApp->LoadIcon(IDI_DIS_BLK));
m_TBarDis.Add(pApp->LoadIcon(IDI_DIS_RED));
m_TBarDis.Add(pApp->LoadIcon(IDI_DIS_YELL));
m_TBarDis.Add(pApp->LoadIcon(IDI_DIS_WHI));

m_wndToolBar.SetImageList(&m_TBarImages);
m_wndToolBar.SetDisabledImageList(&m_TBarDis);

Note The image lists used by the toolbar object must be permanent objects. For this reason, they are commonly data members of an MFC class; in this example, the main frame window class.

Once the image lists are associated with the CToolBarCtrl object, the framework automatically displays the proper button image.

See Also Windows Common Controls and MFC Classes


Using Drop-Down Buttons in a Toolbar Control

Home | Overview | Sample

In addition to standard push buttons, a toolbar can also have drop-down buttons. A drop-down button is usually indicated by the presence of an attached down arrow.

Note The attached down arrow will appear only if the TBSTYLE_EX_DRAWDARROWS extended style has been set.

When the user clicks on this arrow (or the button itself, if no arrow is present), a TBN_DROPDOWN notification message is sent to the parent of the toolbar control. You can then handle this notification and display a popup menu; similar to the behavior of Internet Explorer.

The following procedure illustrates how to implement a drop-down toolbar button with a popup menu:

To implement a drop-down button

  1. Once your CToolBarCtrl object has been created, set the TBSTYLE_EX_DRAWDDARROWS style, using the following code:
    m_wndToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS);
  2. Set the TBSTYLE_DROPDOWN style for any new (InsertButton or AddButtons) or existing (SetButtonInfo) buttons that will be drop-down buttons. The following example demonstrates modifying an existing button in a CToolBarCtrl object:
    TBBUTTONINFO tbi;

tbi.dwMask= TBIF_STYLE;
tbi.cbSize= sizeof(TBBUTTONINFO);
m_wndToolBar.GetToolBarCtrl().GetButtonInfo(ID_EDIT_CUT, &tbi);
tbi.fsStyle |= TBSTYLE_DROPDOWN;
m_wndToolBar.GetToolBarCtrl().SetButtonInfo(ID_EDIT_CUT, &tbi);
  3. Add a WM_NOTIFY handler to the parent class of the toolbar object.

  4. In the new handler, check for the TBN_DROPDOWN notification, using the following code:
    #define lpnm   ((LPNMHDR)lParam)
#define lpnmTB ((LPNMTOOLBAR)lParam)

   switch(lpnm->code)
   {
      case TBN_DROPDOWN:
         //drop down button was hit
         //handle appropriately
         . . .
         return FALSE; //indicates the TBN_DROPDOWN
                       //notification was handled.
   }
  5. If the TBN_DROPDOWN notification has been sent, display the appropriate popup menu. The following code demonstrates one method:
    CMenu menu;
VERIFY(menu.LoadMenu(IDR_MENU1));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
pPopup->TrackPopupMenu(TPM_RIGHTALIGN |
   TPM_RIGHTBUTTON, x, y, this);

See Also Windows Common Controls and MFC Classes


Customizing the Appearance of a Toolbar Control

Home | Overview | Sample

Class CToolBarCtrl provides many styles that affect the appearance (and, occasionally, the behavior) of the toolbar object. Modify the toolbar object by setting the dwCtrlStyle parameter of the CToolBarCtrl::Create (or CToolBar::CreateEx) member function, when you first create the toolbar control.

The following styles affect the "3D" aspect of the toolbar buttons and the placement of the button text:

  • TBSTYLE_FLAT Creates a flat toolbar where both the toolbar and the buttons are transparent. Button text appears under button bitmaps. When this style is used, the button underneath the cursor is automatically highlighted.

  • TBSTYLE_TRANSPARENT Creates a transparent toolbar. In a transparent toolbar, the toolbar is transparent but the buttons are not. Button text appears under button bitmaps.

  • TBSTYLE_LIST Places button text to the right of button bitmaps.

Note To prevent repaint problems, the TBSTYLE_FLAT and TBSTYLE_TRANSPARENT styles should be set before the toolbar object is visible.

The following styles determine if the toolbar allows a user to reposition individual buttons within a toolbar object using drag and drop:

  • TBSTYLE_ALTDRAG Allows users to change a toolbar button's position by dragging it while holding down ALT. If this style is not specified, the user must hold down SHIFT while dragging a button.

    Note The CCS_ADJUSTABLE style must be specified to enable toolbar buttons to be dragged.

  • TBSTYLE_REGISTERDROP Generates TBN_GETOBJECT notification messages to request drop target objects when the mouse pointer passes over toolbar buttons.

The remaining styles affect visual and nonvisual aspects of the toolbar object:

  • TBSTYLE_WRAPABLE Creates a toolbar that can have multiple lines of buttons. Toolbar buttons can "wrap" to the next line when the toolbar becomes too narrow to include all buttons on the same line. Wrapping occurs on separation and nongroup boundaries.

  • TBSTYLE_CUSTOMERASE Generates NM_CUSTOMDRAW notification messages when it processes WM_ERASEBKGND messages.

  • TBSTYLE_TOOLTIPS Creates a tooltip control that an application can use to display descriptive text for the buttons in the toolbar.

For a complete listing of toolbar styles and extended styles, see Toolbar Control and Button Styles and Toolbar Extended Styles in the Platform SDK.

See Also Windows Common Controls and MFC Classes,


Using CToolTipCtrl

Home | Overview | Sample

The CToolTipCtrl class encapsulates the functionality of a tool tip control, a small pop-up window that displays a single line of text describing the purpose of a tool in an application. A tool tip is hidden most of the time, appearing only when the user puts the cursor on a tool and leaves it there for approximately one-half second. The tool tip appears near the cursor and disappears when the user clicks a mouse button or moves the cursor off of the tool.

What do you want to know more about?

  • Methods of Creating Tool Tips

  • Settings for the Tool Tip Control

  • Using CToolTipCtrl to Create and Manipulate a CToolTipCtrl Object

  • Manipulating the Tool Tip Control

See Also Using CToolBarCtrl, Windows Common Controls and MFC Classes


Methods of Creating Tool Tips

Home | Overview | Sample

MFC provides three classes to create and manage the tool tip control: CWnd, CToolBarCtrl, and CToolTipCtrl. The tool tip member functions in these classes wrap the Windows common control API. Class CToolBarCtrl and class CToolTipCtrl are derived from class CWnd.

CWnd provides four member functions to create and manage tool tips: EnableToolTips, CancelToolTips, FilterToolTipMessage, and OnToolHitTest. See these individual member functions for more information about how they implement tool tips.

If you create a toolbar using CToolBarCtrl, you can implement tool tips for that toolbar directly using the following member functions: GetToolTips and SetToolTips. See these individual member functions and CToolBarCtrl: Handling Tool Tip Notifications in the Class Library Reference for more information about how they implement tool tips.

The CToolTipCtrl class provides the functionality of the Windows common tool tip control. A single tool tip control can provide information for more than one tool. A tool is either a window, such as a child window or control, or an application-defined rectangular area within a window's client area.

See Also Windows Common Controls and MFC Classes


Settings for the Tool Tip Control

Home | Overview | Sample

You can set the tool tip control (CToolTipCtrl) to be either active or inactive. When you set it to be active, the tool tip control appears when the cursor is on a tool. When you set it to be inactive, the tool tip control does not appear, even if the cursor is on a tool. Call Activate to activate or deactivate a tool tip control.

You can set an active tool tip to display the tool tip when the cursor is on a tool, whether or not the tool tip control's owner window is active or inactive, by using the TTS_ALWAYSTIP style. If you do not use this style, the tool tip control appears when the tool's owner window is active, but not when it is inactive.

Most applications contain toolbars with tools that correspond to menu commands. For such tools, it is convenient for the tool tip control to display the same text as the corresponding menu item. The system automatically strips the ampersand (&) accelerator characters from all strings passed to a tool tip control, unless the control has the TTS_NOPREFIX style.

See Also Windows Common Controls and MFC Classes


Using CToolTipCtrl to Create and Manipulate a CToolTipCtrl Object

Home | Overview | Sample

Here is an example of CToolTipCtrl usage:

To create and manipulate a CToolTipCtrl

  1. Construct the CToolTipCtrl object.

  2. Call Create to create the Windows tool tip common control and attach it to the CToolTipCtrl object.

  3. Call AddTool to register a tool with the tool tip control, so that the information stored in the tool tip is displayed when the cursor is on the tool.

  4. Call SetToolInfo to set the information that a tool tip maintains for a tool.

  5. Call SetToolRect to set a new bounding rectangle for a tool.

  6. Call HitTest to test a point to determine whether it is within the bounding rectangle of the given tool and, if so, retrieve information about the tool.

  7. Call GetToolCount to retrieve a count of the tools registered with the tool tip control.

See Also Windows Common Controls and MFC Classes


Manipulating the Tool Tip Control

Home | Overview | Sample

Class CToolTipCtrl provides a group of member functions that control the various attributes of the CToolTipCtrl object and the tool tip window.

The initial, pop-up, and reshow durations for the tool tip windows can be set and retrieved with calls to GetDelayTime and SetDelayTime.

Change the appearance of the tool tip windows with the following functions:

  • GetMargin and SetMargin Retrieves and sets the width between the tool tip border and the tool tip text.

  • GetMaxTipWidth and SetMaxTipWidth Retrieves and sets the maximum width of the tool tip window.

  • GetTipBkColor and SetTipBkColor Retrieves and sets the background color of the tool tip window.

  • GetTipTextColor and SetTipTextColor Retrieves and sets the text color of the tool tip window.

In order for the tooltip control to be notified of important messages, such as WM_LBUTTONXXX messages, you must relay the messages to your tooltip control. The best method for this relay is to make a call to CToolTipCtrl::RelayEvent, in the PreTranslateMessage function of the owner window. The following example illustrates one possible method (assuming the tooltip control is called m_ToolTip):

if(pMsg->message== WM_LBUTTONDOWN ||
        pMsg->message== WM_LBUTTONUP ||
        pMsg->message== WM_MOUSEMOVE)
m_ToolTip.RelayEvent(pMsg);

return CMyView::PreTranslateMessage(pMsg);

To immediately remove a tool tip window, call the Pop member function.

See Also Windows Common Controls and MFC Classes


Using CTreeCtrl

Home | Overview | Sample

A tree control, represented by the class CTreeCtrl, is a window that displays a hierarchical list of items, such as the headings in a document, the entries in an index, or the files and directories on a disk. Each item consists of a label and an optional bitmapped image, and each item can have a list of subitems associated with it. By clicking an item, the user can expand and collapse the associated list of subitems. The directory tree in the left-hand pane of the Windows Explorer is an example of a tree control.

What do you want to know more about?

  • CTreeCtrl vs. CTreeView

  • Using Tree Controls

  • Communicating with a Tree Control

  • Tree Control Styles

  • Tree Control Parent and Child Items

  • Tree Control Item Position

  • Tree Control Item Labels

  • Tree Control Label Editing

  • Tree Control Item States Overview

  • Tree Control Image Lists

  • Tree Control Item Selection

  • Tree Control Drag-and-Drop Operations

  • Tree Control Item Information

  • Tree Control Notification Messages

See Also Windows Common Controls and MFC Classes


CTreeCtrl vs. CTreeView

Home | Overview | Sample

MFC provides two classes that encapsulate tree controls: CTreeCtrl and CTreeView. Each class is useful in different situations.

Use CTreeCtrl when you need a plain child window control; for instance, in a dialog box. You'd especially want to use CTreeCtrl if there will be other child controls in the window, as in a typical dialog box.

Use CTreeView when you want the tree control to act like a view window in document/view architecture as well as a tree control. A CTreeView will occupy the entire client area of a frame window or splitter window. It will be automatically resized when its parent window is resized, and it can process command messages from menus, accelerator keys, and toolbars. Since a tree control contains the data necessary to display the tree, the corresponding document object does not have to be complicated — you could even use CDocument as the document type in your document template.

See Also Windows Common Controls and MFC Classes


Using Tree Controls

Home | Overview | Sample

Typical usage of a tree control (CTreeCtrl) follows the pattern below:

  • The control is created. If the control is specified in a dialog box template or if you're using CTreeView, creation is automatic when the dialog box or view is created. If you want to create the tree control as a child window of some other window, use the Create member function.

  • If you want your tree control to use images, set an image list by calling SetImageList. You can also change the indentation by calling SetIndent. A good time to do this is in OnInitDialog (for controls in dialog boxes) or OnInitialUpdate (for views).

  • Put data into the control by calling the CTreeCtrl's InsertItem function once for each data item. InsertItem returns a handle to the item you can use to refer to it later, such as when adding child items. A good time to initialize the data is in OnInitDialog (for controls in dialog boxes) or OnInitialUpdate (for views).

  • As the user interacts with the control, it will send various notification messages. You can specify a function to handle each of the messages you want to handle by adding an ON_NOTIFY_REFLECT macro in your control window's message map or by adding an ON_NOTIFY macro to your parent window's message map. See Tree Control Notification Messages later in this article for a list of possible notifications.

  • Call the various Set member functions to set values for the control. Changes that you can make include setting the indentation and changing the text, image, or data associated with an item.

  • Use the various Get functions to examine the contents of the control. You can also traverse the contents of the tree control with functions that allow you to retrieve handles to parents, children, and siblings of a specified item. You can even sort the children of a particular node.

  • When you're done with the control, make sure it's properly destroyed. If the tree control is in a dialog box or if it's a view, it and the CTreeCtrl object will be destroyed automatically. If not, you need to ensure that both the control and the CTreeCtrl object are properly destroyed.

See Also Windows Common Controls and MFC Classes


Communicating with a Tree Control

Home | Overview | Sample

You'll use different methods for calling member functions in a CTreeCtrl object depending on how the object was created:

  • If the tree control is in a dialog box, use a member variable of type CTreeCtrl that you create in the dialog box class.

  • If the tree control is a child window, use the CTreeCtrl object (or pointer) you used to construct the object.

  • If you're using a CTreeView object, use the function CTreeView::GetTreeCtrl to get a reference to the tree control. You can initialize another reference with this value or assign the address of the reference to a CTreeCtrl pointer.

See Also Windows Common Controls and MFC Classes


Tree Control Styles

Home | Overview | Sample

Tree control (CTreeCtrl) styles govern aspects of a tree control's appearance. You set the initial styles when you create the tree control. You can retrieve and change the styles after creating the tree control by using the GetWindowLong and SetWindowLong Windows functions, specifying GWL_STYLE for the nIndex parameter. For a complete list of styles, see Tree View Control Window Styles in the Platform SDK.

The TVS_HASLINES style enhances the graphic representation of a tree control's hierarchy by drawing lines that link child items to their corresponding parent item. This style does not link items at the root of the hierarchy. To do so, you need to combine the TVS_HASLINES and TVS_LINESATROOT styles.

The user can expand or collapse a parent item's list of child items by double-clicking the parent item. A tree control that has the TVS_SINGLEEXPAND style causes the item being selected to expand and the item being unselected to collapse. If the mouse is used to single-click the selected item and that item is closed, it will be expanded. If the selected item is single-clicked when it is open, it will be collapsed.

A tree control that has the TVS_HASBUTTONS style adds a button to the left side of each parent item. The user can click the button to expand or collapse the child items as an alternative to double-clicking the parent item. TVS_HASBUTTONS does not add buttons to items at the root of the hierarchy. To do so, you must combine TVS_HASLINES, TVS_LINESATROOT, and TVS_HASBUTTONS.

The TVS_EDITLABELS style makes it possible for the user to edit the labels of tree control items. For more information about editing labels, see Tree Control Label Editing later in this article.

The TVS_NOTOOLTIPS style disables the automatic tooltip feature of tree view controls. This feature automatically displays a tooltip, containing the title of the item under the mouse cursor, if the entire title is not currently visible.

See Also Windows Common Controls and MFC Classes


Tree Control Parent and Child Items

Home | Overview | Sample

Any item in a tree control (CTreeCtrl) can have a list of subitems, which are called child items, associated with it. An item that has one or more child items is called a parent item. A child item is displayed below its parent item and is indented to indicate it is subordinate to the parent. An item that has no parent is at the top of the hierarchy and is called a root item.

At any given time, the state of a parent item's list of child items can be either expanded or collapsed. When the state is expanded, the child items are displayed below the parent item. When it is collapsed, the child items are not displayed. The list automatically toggles between the expanded and collapsed states when the user double-clicks the parent item or, if the parent has the TVS_HASBUTTONS style, when the user clicks the button associated with the parent item. An application can expand or collapse the child items by using the Expand member function.

You add an item to a tree control by calling the InsertItem member function. This function returns a handle of the HTREEITEM type, which uniquely identifies the item. When adding an item, you must specify the handle of the new item's parent item. If you specify NULL or the TVI_ROOT value instead of a parent item handle in the TVINSERTSTRUCT structure or hParent parameter, the item is added as a root item.

A tree control sends a TVN_ITEMEXPANDING notification message when a parent item's list of child items is about to be expanded or collapsed. The notification gives you the opportunity to prevent the change or to set any attributes of the parent item that depend on the state of the list of child items. After changing the state of the list, the tree control sends a TVN_ITEMEXPANDED notification message.

When a list of child items is expanded, it is indented relative to the parent item. You can set the amount of indentation by using the SetIndent member function or retrieve the current amount by using the GetIndent member function.

See Also Windows Common Controls and MFC Classes


Tree Control Item Position

Home | Overview | Sample

An item's initial position is set when the item is added to the tree control (CTreeCtrl) by using the InsertItem member function. The member function call specifies the handle of the parent item and the handle of the item after which the new item is to be inserted. The second handle must identify either a child item of the given parent or one of these values: TVI_FIRST, TVI_LAST, or TVI_SORT.

When TVI_FIRST or TVI_LAST is specified, the tree control places the new item at the beginning or end of the given parent item's list of child items. When TVI_SORT is specified, the tree control inserts the new item into the list of child items in alphabetical order based on the text of the item labels.

You can put a parent item's list of child items into alphabetical order by calling the SortChildren member function. This function includes a parameter that specifies whether all levels of child items descending from the given parent item are also sorted in alphabetical order.

The SortChildrenCB member function allows you to sort child items based on criteria that you define. When you call this function, you specify an application-defined callback function that the tree control can call whenever the relative order of two child items needs to be decided. The callback function receives two 32-bit application-defined values for the items being compared and a third 32-bit value that you specify when calling SortChildrenCB.

See Also Windows Common Controls and MFC Classes


Tree Control Item Labels

Home | Overview | Sample

You typically specify the text of an item's label when adding the item to the tree control (CTreeCtrl). The InsertItem member function can pass a TVITEM structure that defines the item's properties, including a string containing the text of the label. InsertItem has several overloads that can be called with various combinations of parameters.

A tree control allocates memory for storing each item; the text of the item labels takes up a significant portion of this memory. If your application maintains a copy of the strings in the tree control, you can decrease the memory requirements of the control by specifying the LPSTR_TEXTCALLBACK value in the pszText member of TV_ITEM or the lpszItem parameter instead of passing actual strings to the tree control. Using LPSTR_TEXTCALLBACK causes the tree control to retrieve the text of an item's label from the application whenever the item needs to be redrawn. To retrieve the text, the tree control sends a TVN_GETDISPINFO notification message, which includes the address of a NMTVDISPINFO structure. You must respond by setting the appropriate members of the included structure.

A tree control uses memory allocated from the heap of the process that creates the tree control. The maximum number of items in a tree control is based on the amount of memory available in the heap. Each item takes 64 bytes.

See Also Windows Common Controls and MFC Classes


Tree Control Label Editing

Home | Overview | Sample

The user can directly edit the labels of items in a tree control (CTreeCtrl) that has the TVS_EDITLABELS style. The user begins editing by clicking the label of the item that has the focus. An application begins editing by using the EditLabel member function. The tree control sends the notification when editing begins and when it is canceled or completed. When editing is completed, you are responsible for updating the item's label, if appropriate.

When label editing begins, a tree control sends a TVN_BEGINLABELEDIT notification message. By processing this notification, you can allow editing of some labels and prevent editing of others. Returning 0 allows editing, and returning nonzero prevents it.

When label editing is canceled or completed, a tree control sends a TVN_ENDLABELEDIT notification message. The lParam parameter is the address of a NMTVDISPINFO structure. The item member is a TVITEM structure that identifies the item and includes the edited text. You are responsible for updating the item's label, if appropriate, perhaps after validating the edited string. The pszText member of TV_ITEM is 0 if editing is canceled.

During label editing, typically in response to the TVN_BEGINLABELEDIT notification message, you can get a pointer to the edit control used for label editing by using the GetEditControl member function. You can call the edit control's SetLimitText member function to limit the amount of text a user can enter or subclass the edit control to intercept and discard invalid characters. Note, however, that the edit control is displayed only after TVN_BEGINLABELEDIT is sent.

See Also Windows Common Controls and MFC Classes


Tree Control Item States Overview

Home | Overview | Sample

Each item in a tree control (CTreeCtrl) has a current state. For example, an item can be selected, disabled, expanded, and so on. For the most part, the tree control automatically sets an item's state to reflect user actions, such as selection of an item. However, you can also set an item's state by using the SetItemState member function and retrieve the current state of an item by using the GetItemState member function. For a complete list of item states, see Tree-View Control Constants in the Platform SDK.

An item's current state is specified by the nState parameter. A tree control might change an item's state to reflect a user action, such as selecting the item or setting the focus to the item. In addition, an application might change an item's state to disable or hide the item or to specify an overlay image or state image.

When you specify or change an item's state, the nStateMask parameter specifies which state bits to set, and the nState parameter contains the new values for those bits. For example, the following example changes the current state of a parent item (specified by hParentItem) in a CTreeCtrl object (m_treeCtrl) to TVIS_EXPANDPARTIAL:

TVITEM curItem;
HTREEITEM hParentItem;

hParentItem= m_treeCtrl.GetSelectedItem();

//modify the parent item to keep the '+' sign
curItem.mask= TVIF_HANDLE;
curItem.hItem= hParentItem;
m_treeCtrl.GetItem(&curItem);

curItem.mask= TVIF_STATE;
curItem.state= TVIS_EXPANDPARTIAL;
curItem.stateMask= TVIS_EXPANDPARTIAL;
m_treeCtrl.SetItem(&curItem);

Another example of changing the state would be to set an item's overlay image. To accomplish this, nStateMask must include the TVIS_OVERLAYMASK value, and nState must include the one-based index of the overlay image shifted left eight bits by using the INDEXTOOVERLAYMASK macro. The index can be 0 to specify no overlay image. The overlay image must have been added to the tree control's list of overlay images by a previous call to the CImageList::SetOverlayImage function. The function specifies the one-based index of the image to add; this is the index used with the INDEXTOOVERLAYMASK macro. A tree control can have up to four overlay images.

To set an item's state image, nStateMask must include the TVIS_STATEIMAGEMASK value, and nState must include the one-based index of the state image shifted left 12 bits by using the INDEXTOSTATEIMAGEMASK macro. The index can be 0 to specify no state image. For more information about overlay and state images, see Tree Control Image Lists.

See Also Windows Common Controls and MFC Classes


Tree Control Image Lists

Home | Overview | Sample

Each item in a tree control (CTreeCtrl) can have a pair of bitmapped images associated with it. The images appear on the left side of an item's label. One image is displayed when the item is selected, and the other is displayed when the item is not selected. For example, an item might display an open folder when it is selected and a closed folder when it is not selected.

To use item images, you must create an image list by constructing a CImageList object and using the CImageList::Create function to create the associated image list. Then add the desired bitmaps to the list, and associate the list with the tree control by using the SetImageList member function. By default, all items display the first image in the image list for both the selected and nonselected states. You can change the default behavior for a particular item by specifying the indexes of the selected and nonselected images when adding the item to the tree control using the InsertItem member function. You can change the indexes after adding an item by using the SetItemImage member function.

A tree control's image lists can also contain overlay images, which are designed to be superimposed on item images. A nonzero value in bits 8 through 11 of a tree control item's state specifies the one-based index of an overlay image (0 indicates no overlay image). Because a 4-bit, one-based index is used, overlay images must be among the first 15 images in the image lists. For more information about tree control item states, see Tree Control Item States Overview earlier in this article.

If a state image list is specified, a tree control reserves space to the left of each item's icon for a state image. An application can use state images, such as checked and cleared check boxes, to indicate application-defined item states. A nonzero value in bits 12 through 15 specifies the one-based index of a state image (0 indicates no state image).

By specifying the I_IMAGECALLBACK value instead of the index of an image, you can delay specifying the selected or nonselected image until the item is about to be redrawn. I_IMAGECALLBACK directs the tree control to query the application for the index by sending the TVN_GETDISPINFO notification message.

The GetImageList member function retrieves the handle of a tree control's image list. This function is useful if you need to add more images to the list. For more information about image lists, see Using CImageList, CImageList in the Class Library Reference, and Image Lists in the Platform SDK.

See Also Windows Common Controls and MFC Classes


Tree Control Item Selection

Home | Overview | Sample

When the selection changes from one item to another, a tree control (CTreeCtrl) sends TVN_SELCHANGING and TVN_SELCHANGED notification messages. Both notifications include a value that specifies whether the change is the result of a mouse click or a keystroke. The notifications also include information about the item that is gaining the selection and the item that is losing the selection. You can use this information to set item attributes that depend on the selection state of the item. Returning TRUE in response to TVN_SELCHANGING prevents the selection from changing; returning FALSE allows the change.

An application can change the selection by calling the SelectItem member function.

See Also Windows Common Controls and MFC Classes


Tree Control Drag-and-Drop Operations

Home | Overview | Sample

A tree control (CTreeCtrl) sends a notification when the user starts to drag an item. The control sends a TVN_BEGINDRAG notification message when the user begins dragging an item with the left mouse button and a TVN_BEGINRDRAG notification message when the user begins dragging with the right button. You can prevent a tree control from sending these notifications by giving the tree control the TVS_DISABLEDRAGDROP style.

You obtain an image to display during a drag operation by calling the CreateDragImage member function. The tree control creates a dragging bitmap based on the label of the item being dragged. Then the tree control creates an image list, adds the bitmap to it, and returns a pointer to the CImageList object.

You must provide the code that actually drags the item. This typically involves using the dragging capabilities of the image list functions and processing the WM_MOUSEMOVE and WM_LBUTTONUP (or WM_RBUTTONUP) messages sent after the drag operation has begun. For more information about the image list functions, see CImageList in the Class Library Reference and Image Lists in the Platform SDK. For more information about dragging a tree control item, see Dragging a Tree View Item, also in the Platform SDK.

If items in a tree control are to be the targets of a drag-and-drop operation, you need to know when the mouse cursor is on a target item. You can find out by calling the HitTest member function. You specify either a point and integer, or the address of a TVHITTESTINFO structure that contains the current coordinates of the mouse cursor. When the function returns, the integer or structure contains a flag indicating the location of the mouse cursor relative to the tree control. If the cursor is over an item in the tree control, the structure contains the handle of the item as well.

You can indicate that an item is the target of a drag-and-drop operation by calling the SetItem member function to set the state to the TVIS_DROPHILITED value. An item that has this state is drawn in the style used to indicate a drag-and-drop target.

See Also Windows Common Controls and MFC Classes


Tree Control Item Information

Home | Overview | Sample

Tree controls (CTreeCtrl) have a number of member functions that retrieve information about items in the control. The GetItem member function retrieves some or all of the data associated with an item. This data could include the item's text, state, images, count of child items, and an application-defined 32-bit data value. There is also a SetItem function that can set some or all of the data associated with an item.

The GetItemState, GetItemText, GetItemData, and GetItemImage member functions retrieve individual attributes of an item. Each of these functions has a corresponding Set function for setting the attributes of an item.

The GetNextItem member function retrieves the tree control item that bears the specified relationship to the current item. This function can retrieve an item's parent, the next or previous visible item, the first child item, and so on. There are also member functions to traverse the tree: GetRootItem, GetFirstVisibleItem, GetNextVisibleItem, GetPrevVisibleItem, GetChildItem, GetNextSiblingItem, GetPrevSiblingItem, GetParentItem, GetSelectedItem, and GetDropHilightItem.

The GetItemRect member function retrieves the bounding rectangle for a tree control item. The GetCount and GetVisibleCount member functions retrieve a count of the items in a tree control and a count of the items that are currently visible in the tree control's window, respectively. You can ensure that a particular item is visible by calling the EnsureVisible member function.

See Also Windows Common Controls and MFC Classes


Tree Control Notification Messages

Home | Overview | Sample

A tree control (CTreeCtrl) sends the following notification messages as WM_NOTIFY messages:

Notification message | Description
TVN_BEGINDRAG | Signals the start of a drag-and-drop operation
TVN_BEGINLABELEDIT | Signals the start of in-place label editing
TVN_BEGINRDRAG | Signals the start of a drag-and-drop operation, using the right mouse button
TVN_DELETEITEM | Signals the deletion of a specific item
TVN_ENDLABELEDIT | Signals the end of label editing
TVN_GETDISPINFO | Requests information that the tree control requires to display an item
TVN_ITEMEXPANDED | Signals that a parent item's list of child items was expanded or collapsed
TVN_ITEMEXPANDING | Signals that a parent item's list of child items is about to be expanded or collapsed
TVN_KEYDOWN | Signals a keyboard event
TVN_SELCHANGED | Signals that the selection has changed from one item to another
TVN_SELCHANGING | Signals that the selection is about to be changed from one item to another
TVN_SETDISPINFO | Notification to update the information maintained for an item

See Also Windows Common Controls and MFC Classes


Control Bar Topics

Home | Overview | How Do I | Sample

Class CWnd is the base class of many other window classes besides the frame windows. Among these derived classes are CControlBar, the base class for all control bars, including:

  • Toolbars, in class CToolBar

  • Status bars, in class CStatusBar

  • Dialog bars, in class CDialogBar

  • Rebars, in class CReBar

Important As of MFC version 4.0, toolbars, status bars, rebars, and tool tips are implemented using Windows 95 functionality instead of the previous implementation specific to MFC.

Brief introductions to the control-bar types follow. For further information, see the links below.

Control Bars

Control bars greatly enhance a program’s usability by providing quick, one-step command actions. Class CControlBar provides the common functionality of all toolbars, status bars, and dialog bars. CControlBar provides the functionality for positioning the control bar in its parent frame window. Because a control bar is usually a child window of a parent frame window, it is a “sibling” to the client view or MDI client of the frame window. A control-bar object uses information about its parent window’s client rectangle to position itself. Then it alters the parent’s remaining client-window rectangle so that the client view or MDI client window fills the rest of the client window.

Note If a button on the control bar doesn’t have a COMMAND or UPDATE_COMMAND_UI handler, the framework automatically disables the button.

Toolbars

A toolbar is a control bar that displays a row of bitmapped buttons that activate commands. Pressing a toolbar button is equivalent to choosing a menu item. The buttons can be configured to appear and behave as pushbuttons, radio buttons, or check boxes. A toolbar is usually aligned to the top of a frame window, but an MFC toolbar can “dock” to any side of its parent window or float in its own mini-frame window. A toolbar can also “float” over the application’s windows, and you can change its size and drag it. A toolbar can also display tool tips as the user moves the mouse over the toolbar’s buttons. A tool tip is a tiny popup window that briefly describes the button’s purpose.

Note As of MFC version 4.0, class CToolBar uses the Windows toolbar common control. A CToolBar contains a CToolBarCtrl. Older toolbars are still supported, however. See the article ToolBars.

Status Bars

A status bar is a control bar that contains text-output panes, or “indicators.” The output panes are commonly used as message lines and as status indicators. Message line examples include the command help-message lines that briefly explain the selected menu or toolbar command in the leftmost pane of the default status bar created by AppWizard. Status indicator examples include the SCROLL LOCK, NUM LOCK, and other keys. Status bars are usually aligned to the bottom of a frame window. See class CStatusBar and class CStatusBarCtrl.

Dialog Bars

A dialog bar is a control bar, based on a dialog-template resource, with the functionality of a modeless dialog box. Dialog bars can contain any Windows control. As in a dialog box, the user can tab among the controls. Dialog bars can be aligned to the top, bottom, left, or right side of a frame window. See class CDialogBar.

Rebars

A rebar is a control bar that provides docking, layout, state, and persistence information for rebar controls. A rebar object can contain a variety of child windows, usually other controls, including edit boxes, toolbars, and list boxes. A rebar object can display its child windows over a specified bitmap. It can be automatically or manually resized by clicking or dragging its gripper bar. See Class CReBar.


Dialog Bar Topics

Home | Overview | How Do I | Sample

A dialog bar is a toolbar — a kind of control bar that can contain any kind of control. Because it has the characteristics of a modeless dialog box, a CDialogBar object provides a more powerful toolbar.

There are several key differences between a toolbar and a CDialogBar object. A CDialogBar object is created from a dialog-template resource, which you can create with the Visual C++ dialog editor and which can contain any kind of Windows control. The user can tab from control to control. And you can specify an alignment style to align the dialog bar with any part of the parent frame window or even to leave it in place if the parent is resized. The following figure shows a dialog bar with a variety of controls.

A Dialog Bar

In other respects, working with a CDialogBar object is like working with a modeless dialog box. Use the dialog editor to design and create the dialog resource.

One of the virtues of dialog bars is that they can include controls other than buttons.

While it is normal to derive your own dialog classes from CDialog, you do not typically derive your own class for a dialog bar. Dialog bars are extensions to a main window and any dialog-bar control-notification messages, such as BN_CLICKED or EN_CHANGE, will be sent to the parent of the dialog bar — the main window.

For more information about dialog bars, see class CDialogBar in the Class Library Reference.


Dialog Box Topics

Home | Overview | How Do I | Sample | Tutorial

Applications for Windows frequently communicate with the user through dialog boxes. Class CDialog provides an interface for managing dialog boxes, the Visual C++ dialog editor makes it easy to design dialog boxes and create their dialog-template resources, and ClassWizard simplifies the process of initializing and validating the controls in a dialog box and of gathering the values entered by the user.

What do you want to know more about?

  • Dialog components

  • Modal and modeless dialog boxes

  • Property sheets and property pages in a dialog box

  • Creating a dialog resource template

  • The life cycle of a dialog box

  • Dialog data exchange (DDX) and validation (DDV)

  • Type-safe access to controls in a dialog box

  • Mapping Windows messages to your class

  • Common dialog classes

  • Dialog boxes in OLE


Dialog-Box Components in the Framework

Home | Overview | How Do I | Sample | Tutorial

In the MFC framework, a dialog box has two components:

  • A dialog-template resource that specifies the dialog box’s controls and their placement.

    The dialog resource stores a dialog template from which Windows creates the dialog window and displays it. The template specifies the dialog box’s characteristics, including its size, location, style, and the types and positions of the dialog box’s controls. You will usually use a dialog template stored as a resource, but you can also create your own template in memory.

  • A dialog class, derived from CDialog, to provide a programmatic interface for managing the dialog box.

    A dialog box is a window and will be attached to a Windows window when visible. When the dialog window is created, the dialog-template resource is used as a template for creating child window controls for the dialog box.

See Also Life Cycle of a Dialog Box


Modal and Modeless Dialog Boxes

Home | Overview | How Do I | Sample | Tutorial

You can use class CDialog to manage two kinds of dialog boxes:

  • Modal dialog boxes, which require the user to respond before continuing the program

  • Modeless dialog boxes, which stay on the screen and are available for use at any time but permit other user activities

The resource editing and ClassWizard procedures for creating a dialog template are the same for modal and modeless dialog boxes.

Creating a dialog box for your program requires the following steps:

  1. Use the dialog editor to design the dialog box and create its dialog-template resource.

  2. Use ClassWizard to create a dialog class.

  3. Use ClassWizard to connect the dialog resource’s controls to message handlers in the dialog class.

  4. Use ClassWizard to add data members associated with the dialog box’s controls and to specify dialog data exchange and dialog data validations for the controls.

See Also Life Cycle of a Dialog Box


Property Sheets and Property Pages

Home | Overview | How Do I | Sample | Tutorial

An MFC dialog box can take on a “tab dialog” look by incorporating property sheets and property pages. Called a “property sheet” in MFC, this kind of dialog box, similar to many dialog boxes in Microsoft Word, Excel, and Visual C++, appears to contain a stack of tabbed sheets, much like a stack of file folders seen from front to back, or a group of cascaded windows. Controls on the front tab are visible; only the labeled tab is visible on the rear tabs. Property sheets are particularly useful for managing large numbers of properties or settings that fall fairly neatly into several groups. Typically, one property sheet can simplify a user interface by replacing several separate dialog boxes.

As of MFC version 4.0, property sheets and property pages are implemented using the common controls that come with Windows 95 and Windows NT version 3.51 and later.

Property sheets are implemented with classes CPropertySheet and CPropertyPage (described in the Class Library Reference). CPropertySheet defines the overall dialog box, which can contain multiple “pages” based on CPropertyPage.

For information on creating and working with property sheets, see the article Property Sheet Topics.

See Also Life Cycle of a Dialog Box


Creating the Dialog Resource

Home | Overview | How Do I | Sample | Tutorial

To design the dialog box and create the dialog resource, you use the dialog editor. In the dialog editor, you can:

  • Adjust the size and location your dialog box will have when it appears.

  • Drag various kinds of controls from a controls palette and drop them where you want them in the dialog box.

  • Position the controls with alignment buttons on the toolbar.

  • Test your dialog box by simulating the appearance and behavior it will have in your program. In Test mode, you can manipulate the dialog box’s controls by typing text in text boxes, clicking pushbuttons, and so on.

When you finish, your dialog-template resource is stored in your application’s resource script file. You can edit it later if needed. For a full description of how to create and edit dialog resources, see dialog editor documentation in the Visual C++ User’s Guide. This technique is also used to create the dialog-template resources for CFormView and CRecordView classes.

When the dialog box’s appearance suits you, use ClassWizard to create a dialog class and map its messages, as discussed in Creating a Dialog Class with ClassWizard.

See Also Life Cycle of a Dialog Box


Creating a Dialog Class with ClassWizard

Home | Overview | How Do I | Sample | Tutorial

The following table lists dialog-related tasks that ClassWizard helps you manage.

Dialog-Related Tasks

Task | Apply to . . .
Create a new CDialog-derived class to manage your dialog box. | Each dialog box.
Map Windows messages to your dialog class. | Each message you want handled.
Declare class member variables to represent the controls in the dialog box. | Each control that yields a text or numeric value you want to access from your program.
Specify how data is to be exchanged between the controls and the member variables. | Each control you want to access from your program.
Specify validation rules for the member variables. | Each control that yields a text or numeric value, if desired.

You can also do many of these tasks with WizardBar.

What do you want to know more about?

  • Creating your dialog class

  • Handling Windows messages in your dialog box

  • Dialog data exchange and validation

See Also Life Cycle of a Dialog Box


Creating Your Dialog Class

Home | Overview | How Do I | Sample | Tutorial

For each dialog box in your program, create a new dialog class to work with the dialog resource.

Adding a Class explains how to create a new dialog class. When you create a dialog class with ClassWizard, ClassWizard writes the following items in the .H and .CPP files you specify:

In the .H file:

  • A class declaration for the dialog class. The class is derived from CDialog.

In the .CPP file:

  • A message map for the class.

  • A standard constructor for the dialog box.

  • An override of the DoDataExchange member function. Edit this function with ClassWizard. It is used for dialog data exchange and validation capabilities as described later in Dialog data exchange and validation.

See Also Life Cycle of a Dialog Box


Life Cycle of a Dialog Box

Home | Overview | How Do I | Sample | Tutorial

During the life cycle of a dialog box, the user invokes the dialog box, typically inside a command handler that creates and initializes the dialog object, the user interacts with the dialog box, and the dialog box closes.

For modal dialog boxes, your handler gathers any data the user entered once the dialog box closes. Since the dialog object exists after its dialog window has closed, you can simply use the member variables of your dialog class to extract the data.

For modeless dialog boxes, you may often extract data from the dialog object while the dialog box is still visible. At some point, the dialog object is destroyed; when this happens depends on your code.

What do you want to know more about?

  • Creating and displaying dialog boxes

  • Creating modal dialog boxes

  • Creating modeless dialog boxes

  • Using a dialog template in memory

  • Setting the dialog box’s background color

  • Initializing the dialog box

  • Handling Windows messages in my dialog box

  • Retrieving data from the dialog object

  • Closing the dialog box

  • Destroying the dialog box

  • Dialog data exchange (DDX) and validation (DDV)

  • Property sheet dialog boxes


Creating and Displaying Dialog Boxes

Home | Overview | How Do I | Sample | Tutorial

Creating a dialog object is a two-phase operation. First, construct the dialog object, then create the dialog window. Modal and modeless dialog boxes differ somewhat in the process used to create and display them. The following table lists how modal and modeless dialog boxes are normally constructed and displayed.

Dialog Creation

Dialog type | How to create it
Modeless | Construct CDialog, then call Create member function.
Modal | Construct CDialog, then call DoModal member function.

You can, if you want, create your dialog box from an in-memory dialog template that you have constructed rather than from a dialog template resource. This is an advanced topic, however.

See Also Life Cycle of a Dialog Box


Creating Modal Dialog Boxes

Home | Overview | How Do I | Sample | Tutorial

To create a modal dialog box, call either of the two public constructors declared in CDialog. Next, call the dialog object’s DoModal member function to display the dialog box and manage interaction with it until the user chooses OK or Cancel. This management by DoModal is what makes the dialog box modal. For modal dialog boxes, DoModal loads the dialog resource.

See Also Life Cycle of a Dialog Box


Creating Modeless Dialog Boxes

Home | Overview | How Do I | Sample | Tutorial

For a modeless dialog box, you must provide your own public constructor in your dialog class. To create a modeless dialog box, call your public constructor and then call the dialog object’s Create member function to load the dialog resource. You can call Create either during or after the constructor call. If the dialog resource has the property WS_VISIBLE, the dialog box appears immediately. If not, you must call its ShowWindow member function.

See Also Life Cycle of a Dialog Box


Using a Dialog Template in Memory

Home | Overview | How Do I | Sample | Tutorial

Instead of using the methods given in the Dialog Creation table , you can create either kind of dialog box indirectly from a dialog template in memory. For more information, see class CDialog in the Class Library Reference.

See Also Life Cycle of a Dialog Box


Setting the Dialog Box's Background Color

Setting the Dialog Box’s Background Color

Home | Overview | How Do I | Sample | Tutorial

You can set the background color of your dialog boxes by calling the CWinApp member function SetDialogBkColor in your InitInstance override. The color you set is used for all dialog boxes and message boxes.

See Also Life Cycle of a Dialog Box


Initializing the Dialog Box

Home | Overview | How Do I | Sample | Tutorial

After the dialog box and all of its controls are created but just before the dialog box (of either type) appears on the screen, the dialog object’s OnInitDialog member function is called. For a modal dialog box, this occurs during the DoModal call. For a modeless dialog box, OnInitDialog is called when Create is called. You typically override OnInitDialog to initialize the dialog box’s controls, such as setting the initial text of an edit box. You must call the OnInitDialog member function of the base class, CDialog, from your OnInitDialog override.

If you want to set your dialog box’s background color (and that of all other dialog boxes in your application), see Setting the Dialog Box’s Background Color.

See Also Life Cycle of a Dialog Box


Handling Windows Messages in Your Dialog Box

Home | Overview | How Do I | Sample | Tutorial

Dialog boxes are windows, so they can handle Windows messages if you supply the appropriate handler functions. When you create your dialog class with ClassWizard, the wizard adds an empty message map to the class. Use ClassWizard to map any Windows messages or commands you want your class to handle.

See Mapping Windows Messages to Your Dialog Class for more information.

See Also Life Cycle of a Dialog Box


Retrieving Data from the Dialog Object

Home | Overview | How Do I | Sample | Tutorial

The framework provides an easy way to initialize the values of controls in a dialog box and to retrieve values from the controls. The more laborious manual approach is to call functions such as the SetDlgItemText and GetDlgItemText member functions of class CWnd, which apply to control windows. With these functions, you access each control individually to set or get its value, calling functions such as SetWindowText and GetWindowText. The framework’s approach automates both initialization and retrieval.

Dialog data exchange (DDX) lets you exchange data between the controls in the dialog box and member variables in the dialog object more easily. This exchange works both ways. To initialize the controls in the dialog box, you can set the values of data members in the dialog object, and the framework will transfer the values to the controls before the dialog box is displayed. Then you can at any time update the dialog data members with data entered by the user. At that point, you can use the data by referring to the data member variables.

You can also arrange for the values of dialog controls to be validated automatically with dialog data validation (DDV).

Use ClassWizard to add DDX and DDV capabilities to a dialog class. DDX and DDV are explained in more detail in Dialog Data Exchange and Validation.

For a modal dialog box, you can retrieve any data the user entered when DoModal returns IDOK but before the dialog object is destroyed. For a modeless dialog box, you can retrieve data from the dialog object at any time by calling UpdateData with the argument TRUE and then accessing dialog class member variables. This subject is discussed in more detail in Dialog Data Exchange and Validation.

See Also Life Cycle of a Dialog Box


Closing the Dialog Box

Home | Overview | How Do I | Sample | Tutorial

A modal dialog box closes when the user chooses one of its buttons, typically the OK button or the Cancel button. Choosing the OK or Cancel button causes Windows to send the dialog object a BN_CLICKED control-notification message with the button’s ID, either IDOK or IDCANCEL. CDialog provides default handler functions for these messages: OnOK and OnCancel. The default handlers call the EndDialog member function to close the dialog window. You can also call EndDialog from your own code. For more information, see the EndDialog member function of class CDialog in the Class Library Reference.

To arrange for closing and deleting a modeless dialog box, override PostNcDestroy and invoke the delete operator on the this pointer. Destroying the Dialog Box explains what happens next.

See Also Life Cycle of a Dialog Box


Destroying the Dialog Box

Home | Overview | How Do I | Sample | Tutorial

Modal dialog boxes are normally created on the stack frame and destroyed when the function that created them ends. The dialog object’s destructor is called when the object goes out of scope.

Modeless dialog boxes are normally created and owned by a parent view or frame window — the application’s main frame window or a document frame window. The default OnClose handler calls DestroyWindow, which destroys the dialog-box window. If the dialog box stands alone, with no pointers to it or other special ownership semantics, you should override PostNcDestroy to destroy the C++ dialog object. You should also override OnCancel and call DestroyWindow from within it. If not, the owner of the dialog box should destroy the C++ object when it is no longer necessary.

See Also Life Cycle of a Dialog Box


Dialog Data Exchange and Validation

Home | Overview | How Do I | Sample | Tutorial

Dialog data exchange (DDX) is an easy way to initialize the controls in your dialog box and to gather data input by the user. Dialog data validation (DDV) is an easy way to validate data entry in a dialog box. To take advantage of DDX and DDV in your dialog boxes, use ClassWizard to create the data members and set their data types and specify validation rules. For additional information about DDX/DDV and for examples, see Working with Dialog Box Data and Adding a Dialog Box.

What do you want to know more about?

  • Dialog data exchange

  • Dialog data validation

See Also Life Cycle of a Dialog Box


Dialog Data Exchange

Home | Overview | How Do I | Sample | Tutorial

If you use the DDX mechanism, you set the initial values of the dialog object’s member variables, typically in your OnInitDialog handler or the dialog constructor. Immediately before the dialog is displayed, the framework’s DDX mechanism transfers the values of the member variables to the controls in the dialog box, where they appear when the dialog box itself appears in response to DoModal or Create. The default implementation of OnInitDialog in CDialog calls the UpdateData member function of class CWnd to initialize the controls in the dialog box.

The same mechanism transfers values from the controls to the member variables when the user clicks the OK button (or whenever you call the UpdateData member function with the argument TRUE). The dialog data validation mechanism validates any data items for which you specified validation rules.

The following figure illustrates dialog data exchange.

Dialog Data Exchange

UpdateData works in both directions, as specified by the BOOL parameter passed to it. To carry out the exchange, UpdateData sets up a CDataExchange object and calls your dialog class’s override of CDialog’s DoDataExchange member function. DoDataExchange takes an argument of type CDataExchange. The CDataExchange object passed to UpdateData represents the context of the exchange, defining such information as the direction of the exchange.

When you (or ClassWizard) override DoDataExchange, you specify a call to one DDX function per data member (control). Each DDX function knows how to exchange data in both directions based on the context supplied by the CDataExchange argument passed to your DoDataExchange by UpdateData.

MFC provides many DDX functions for different kinds of exchange. The following example shows a DoDataExchange override in which two DDX functions and one DDV function are called:

void CMyDialog::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);    // Call base class version
    //{{AFX_DATA_MAP(CMyDialog)
    DDX_Check(pDX, IDC_MY_CHECKBOX, m_bVar);
    DDX_Text(pDX, IDC_MY_TEXTBOX, m_strName);
    DDV_MaxChars(pDX, m_strName, 20);
    //}}AFX_DATA_MAP
}

The DDX_ and DDV_ lines between the //{{AFX_DATA_MAP and //}}AFX_DATA_MAP delimiters are a data map. The sample DDX and DDV functions shown are for a check-box control and an edit-box control, respectively.

If the user cancels a modal dialog box, the OnCancel member function terminates the dialog box and DoModal returns the value IDCANCEL. In that case, no data is exchanged between the dialog box and the dialog object.

See Also Life Cycle of a Dialog Box, Dialog Data Validation


Dialog Data Validation

Home | Overview | How Do I | Sample | Tutorial

You can specify validation in addition to data exchange by calling DDV functions, as shown in the example in Dialog Data Exchange. The DDV_MaxChars call in the example validates that the string entered in the text-box control is not longer than 20 characters. The DDV function typically alerts the user with a message box if the validation fails and puts the focus on the offending control so the user can reenter the data. A DDV function for a given control must be called immediately after the DDX function for the same control.

You can also define your own custom DDX and DDV routines. For details on this and other aspects of DDX and DDV, see MFC Technical Note 26.

ClassWizard will write all of the DDX and DDV calls in the data map for you. Do not manually edit the lines in the data map between the delimiting comments.

See Also Life Cycle of a Dialog Box, Dialog Data Exchange


Type-Safe Access to Controls in a Dialog Box

Home | Overview | How Do I | Sample | Tutorial

The controls in a dialog box can use the interfaces of MFC control classes such as CListBox and CEdit. You can create a control object and attach it to a dialog control. Then you can access the control through its class interface, calling member functions to operate on the control. The methods described here are designed to give you type-safe access to a control. This is especially useful for controls such as edit boxes and list boxes.

There are two approaches to making a connection between a control in a dialog box and a C++ control member variable in a CDialog-derived class:

  • Without ClassWizard

  • With ClassWizard


Type-Safe Access to Controls Without ClassWizard

Home | Overview | How Do I | Sample | Tutorial

The first approach to creating type-safe access to controls uses an inline member function to cast the return type of class CWnd’s GetDlgItem member function to the appropriate C++ control type, as in this example:

// Declared inline in class CMyDialog
CButton* GetMyCheckbox()
{
    return (CButton*)GetDlgItem(ID_MYCHECKBOX);
}

You can then use this member function to access the control in a type-safe manner with code similar to the following:

GetMyCheckbox()->SetState(TRUE);

See Also Type-Safe Access to Controls With ClassWizard


Type-Safe Access to Controls With ClassWizard

Home | Overview | How Do I | Sample | Tutorial

If you are familiar with DDX features, you can use the Control property in ClassWizard to create type-safe access. This approach is easier than creating controls without ClassWizard.

If you simply want access to a control’s value, DDX provides it. If you want to do more than access a control’s value, use ClassWizard to add a member variable of the appropriate class to your dialog class. Attach this member variable to the Control property.

Member variables can have a Control property instead of a Value property. The Value property refers to the type of data returned from the control, such as CString or int. The Control property enables direct access to the control through a data member whose type is one of the control classes in MFC, such as CButton or CEdit.

Note For a given control, you can, if you wish, have multiple member variables with the Value property and at most one member variable with the Control property. You can have only one MFC object mapped to a control because multiple objects attached to a control, or any other window, would lead to an ambiguity in the message map.

You can use this object to call any member functions for the control object. Such calls affect the control in the dialog box. For example, for a check-box control represented by a variable m_checkboxDefault, of type CButton, you could call:

m_checkboxDefault.SetState(TRUE);

Here the member variable m_checkboxDefault serves the same purpose as the member function GetMyCheckbox shown in Type-Safe Access to Controls Without ClassWizard. If the check box is not an auto check box, you would still need a handler in your dialog class for the BN_CLICKED control-notification message when the button is clicked.

For more information about controls, see Controls.

See Also Life Cycle of a Dialog Box, Type-Safe Access to Controls Without ClassWizard


Mapping Windows Messages to Your Class

Home | Overview | How Do I | Sample | Tutorial

If you need your dialog box to handle Windows messages, override the appropriate handler functions. To do so, use ClassWizard to map the messages to the dialog class. This writes a message-map entry for each message and adds the message-handler member functions to the class. Use the Visual C++ source code editor to write code in the message handlers.

You can also override member functions of CDialog and its base classes, especially CWnd.

What do you want to know more about?

  • Message handling and mapping

  • ClassWizard and WizardBar

  • Commonly overridden member functions

  • Commonly added member functions

See Also Life Cycle of a Dialog Box


Commonly Overridden Member Functions

Home | Overview | How Do I | Sample | Tutorial

The following table lists the most likely member functions to override in your CDialog-derived class.

Commonly Overridden Member Functions of Class CDialog

Member function | Message it responds to | Purpose of the override
OnInitDialog | WM_INITDIALOG | Initialize the dialog box’s controls.
OnOK | BN_CLICKED for button IDOK | Respond when the user clicks the OK button.
OnCancel | BN_CLICKED for button IDCANCEL | Respond when the user clicks the Cancel button.

OnInitDialog, OnOK, and OnCancel are virtual functions. To override them, you declare an overriding function in your derived dialog class using ClassWizard. In these cases, ClassWizard will not add any message-map entries because they are not necessary.

OnInitDialog is called just before the dialog box is displayed. You must call the default OnInitDialog handler from your override — usually as the first action in the handler. By default, OnInitDialog returns TRUE to indicate that the focus should be set to the first control in the dialog box.

OnOK is typically overridden for modeless but not modal dialog boxes. If you override this handler for a modal dialog box, call the base class version from your override — to ensure that EndDialog is called — or call EndDialog yourself.

OnCancel is usually overridden for modeless dialog boxes.

For more information about these member functions, see class CDialog in the Class Library Reference and the discussion on Life Cycle of a Dialog Box.

See Also Commonly Added Member Functions


Commonly Added Member Functions

Home | Overview | How Do I | Sample | Tutorial

If your dialog box contains pushbuttons other than OK or Cancel, you need to write message-handler member functions in your dialog class to respond to the control-notification messages they generate. For an example, see Adding a Dialog Box. You can also handle control-notification messages from other controls in your dialog box.

See Also Life Cycle of a Dialog Box, Commonly Overridden Member Functions


Common Dialog Classes

Home | Overview | How Do I | Sample | Tutorial

In addition to class CDialog, MFC supplies several classes derived from CDialog that encapsulate commonly used dialog boxes, as shown in the following table. The dialog boxes encapsulated are called the “common dialog boxes” and are part of the Windows common dialog library (COMMDLG.DLL). The dialog-template resources and code for these classes are provided in the Windows common dialog boxes that are part of Windows versions 3.1 and later.

Common Dialog Classes

Derived dialog class | Purpose
CColorDialog | Lets user select colors.
CFileDialog | Lets user select a filename to open or to save.
CFindReplaceDialog | Lets user initiate a find or replace operation in a text file.
CFontDialog | Lets user specify a font.
CPrintDialog | Lets user specify information for a print job.

For more information about the common dialog classes, see the individual class names in the Class Library Reference. MFC also supplies a number of standard dialog classes used for OLE. For information about these classes, see the base class, COleDialog, in the Class Library Reference.

Three other classes in MFC have dialog-like characteristics. For information about classes CFormView, CRecordView, and CDaoRecordView, see the classes in the Class Library Reference. For information about class CDialogBar, see Dialog Bar Topics.

See Also Life Cycle of a Dialog Box, Dialog Boxes in OLE


Dialog Boxes in OLE

Home | Overview | How Do I | Sample | Tutorial

While a user runs an OLE-enabled application, there are times when the application needs information from the user in order to carry out the operation. The MFC OLE classes provide a number of dialog boxes to gather the required information. This article lists the tasks handled by the OLE dialog boxes and the classes needed to display those dialog boxes. For full details on OLE dialog boxes and the structures used to customize their behavior, see the Class Library Reference and see the User Interface Dialog Help (OLE2UI.HLP) file included with the OLE SDK.

Insert Object

This dialog box allows the user to insert newly created or existing objects into the compound document. It also allows the user to choose to display the item as an icon and enables the Change Icon command button. Display this dialog box when the user chooses Insert Object from the Edit menu. Use the COleInsertDialog class to display this dialog box. Note that you cannot insert an MDI application into itself. An application that is a container/server cannot be inserted into itself unless it is an SDI application.

Paste Special

This dialog box allows the user to control the format used when pasting data into a compound document. The user can choose the format of the data, whether to embed or link the data, and whether to display it as an icon. Display this dialog box when the user chooses Paste Special from the Edit menu. Use the COlePasteSpecialDialog class to display this dialog box.

Change Icon

This dialog box allows the user to select which icon is displayed to represent the linked or embedded item. Display this dialog box when the user chooses Change Icon from the Edit menu or chooses the Change Icon button in either the Paste Special or Convert dialog boxes. Also display it when the user opens the Insert Object dialog box and chooses Display as Icon. Use the COleChangeIconDialog class to display this dialog box.

Convert

This dialog box allows the user to change the type of an embedded or linked item. For example, if you have embedded a metafile in a compound document and later want to use another application to modify the embedded metafile, you can use the Convert dialog box. This dialog box is usually displayed by clicking item type Object on the Edit menu and then, on the cascading menu, clicking Convert. Use the COleConvertDialog class to display this dialog box. For an example, run the MFC OLE sample OCLIENT.

Edit Links or Update Links

The Edit Links dialog box allows the user to change information about the source of a linked object. The Update Links dialog box verifies the sources of all the linked items in the current dialog box and displays the Edit Links dialog box if necessary. Display the Edit Links dialog box when the user chooses Links from the Edit menu. The Update Links dialog box is usually displayed when a compound document is first opened. Use either the COleLinksDialog or the COleUpdateDialog class, depending on which dialog box you want to display.

Server Busy or Server Not Responding

The Server Busy dialog box is displayed when the user attempts to activate an item and the server is currently unable to handle the request, usually because the server is in use by another user or task. The Server Not Responding dialog box is displayed if the server does not respond to the activation request at all. These dialog boxes are displayed via COleMessageFilter, based on an implementation of the OLE interface IMessageFilter, and the user can decide whether to attempt the activation request again. Use the COleBusyDialog class to display this dialog box.

See Also Life Cycle of a Dialog Box, OLE in MFC: Overview


Document/View Architecture Topics

Home | Overview | How Do I | Sample | Tutorial

The parts of the MFC framework most visible both to the user and to you, the programmer, are the document and view. Most of your work in developing an application with the framework goes into writing your document and view classes. This article family describes:

  • The purposes of documents and views and how they interact in the framework.

  • What you must do to implement them.

The CDocument class provides the basic functionality for programmer-defined document classes. A document represents the unit of data that the user typically opens with the Open command on the File menu and saves with the Save command on the File menu.

The CView class provides the basic functionality for programmer-defined view classes. A view is attached to a document and acts as an intermediary between the document and the user: the view renders an image of the document on the screen and interprets user input as operations upon the document. The view also renders the image for both printing and print preview.

The following figure shows the relationship between a document and its view.

Document and View

The document/view implementation in the class library separates the data itself from its display and from user operations on the data. All changes to the data are managed through the document class. The view calls this interface to access and update the data.

Documents, their associated views, and the frame windows that frame the views are created by a document template. The document template is responsible for creating and managing all documents of one document type.

What do you want to know more about?

  • The document and view classes created by AppWizard

  • A portrait of how document/view works

  • Advantages of using the document/view architecture

  • How MFC creates documents and views using document templates

  • Documents

  • Views

  • Multiple document types

  • Multiple views

  • Multiple frame windows

  • Splitter windows

  • Initializing documents and views

  • Cleaning up documents and views

  • Alternatives to the document/view architecture

  • Using database classes with documents and views

  • Using database classes without documents and views

  • Serializing document data to persistent storage


A Portrait of the Document/View Architecture

Home | Overview | How Do I | Sample | Tutorial

Documents and views are paired in a typical MFC application. Data is stored in the document, but the view has privileged access to the data. The separation of document from view separates the storage and maintenance of data from its display.

Gaining Access to Document Data from the View

The view accesses its document's data either with the GetDocument function, which returns a pointer to the document, or by making the view class a C++ friend of the document class. The view then uses its access to the data to obtain the data when it is ready to draw or otherwise manipulate it.

For example, from the view's OnDraw member function, the view uses GetDocument to obtain a document pointer. Then it uses that pointer to access a CString data member in the document. The view passes the string to the TextOut function. To see the code for this example, see Drawing in a View.

User Input to the View

The view might also interpret a mouse click within itself as either selection or editing of data. Similarly it might interpret keystrokes as data entry or editing. Suppose the user types a string in a view that manages text. The view obtains a pointer to the document and uses the pointer to pass the new data to the document, which stores it in some data structure.

Updating Multiple Views of the Same Document

In an application with multiple views of the same document — such as a splitter window in a text editor — the view first passes the new data to the document. Then it calls the document's UpdateAllViews member function, which tells all views of the document to update themselves, reflecting the new data. This synchronizes the views.

What do you want to know more about?

  • Advantages of the document/view architecture

  • Alternatives to the document/view architecture


Advantages of the Document/View Architecture

Home | Overview | How Do I | Sample | Tutorial

The key advantage to using the MFC document/view architecture is that the architecture supports multiple views of the same document particularly well. (If you don't need multiple views and the small overhead of document/view is excessive in your application, you can avoid the architecture. See Alternatives to the Document/View Architecture.)

Suppose your application lets users view numerical data either in spreadsheet form or in chart form. A user might want to see simultaneously both the raw data, in spreadsheet form, and a chart that results from the data. You display these separate views in separate frame windows or in splitter panes within a single window. Now suppose the user can edit the data in the spreadsheet and see the changes instantly reflected in the chart.

In MFC, the spreadsheet view and the chart view would be based on different classes derived from CView. Both views would be associated with a single document object. The document stores the data (or perhaps obtains it from a database). Both views access the document and display the data they retrieve from it.

When a user updates one of the views, that view object calls CDocument::UpdateAllViews. That function notifies all of the document's views, and each view updates itself using the latest data from the document. The single call to UpdateAllViews synchronizes the different views.

This scenario would be difficult to code without the separation of data from view, particularly if the views stored the data themselves. With document/view, it's easy. The framework does most of the coordination work for you.

What do you want to know more about?

  • Alternatives to document/view

  • CDocument

  • CView

  • CDocument::UpdateAllViews

  • CView::GetDocument


Document and View Classes Created by AppWizard

Home | Overview | How Do I | Sample | Tutorial

AppWizard gives you a head start on your program development by creating skeletal document and view classes for you. You can then use ClassWizard to map commands and messages to these classes and the Visual C++ source code editor to write their member functions.

The document class created by AppWizard is derived from class CDocument. The view class is derived from CView. The names that AppWizard gives these classes and the files that contain them are based on the project name you supply in the AppWizard dialog box. From AppWizard, you can use the Classes dialog box to alter the default names.

Some applications might need more than one document class, view class, or frame-window class. For more information, see Multiple Document Types, Views, and Frame Windows.


Alternatives to the Document/View Architecture

Home | Overview | How Do I | Sample | Tutorial

MFC applications normally use the document/view architecture to manage information, file formats, and the visual representation of data to users. For the majority of desktop applications, the document/view architecture is an appropriate and efficient application architecture. This architecture separates data from viewing and, in most cases, simplifies your application and reduces redundant code.

However, the document/view architecture is not appropriate for some situations. Consider these examples:

  • If you are porting an application written in C for Windows, you might want to complete your port before adding document/view support to your application.

  • If you are writing a lightweight utility, you might find that you can do without the document/view architecture.

  • If your original code already mixes data management with data viewing, moving the code to the document/view model is not worth the effort because you must separate the two. You might prefer to leave the code as is.

To create an application that does not use the document/view architecture, clear the Document/View architecture support check box in step 1 of the MFC AppWizard. See The MFC AppWizard (EXE version): Step-by-Step for details on the MFC AppWizard.

Note Dialog-based applications produced by AppWizard do not use the document/view architecture, so the Document/View architecture support check box is disabled if you select the dialog application type.

The Visual C++ wizards, as well as the source and dialog editors, work with the generated application just as they would with any other Wizard-generated application. The application can support toolbars, scrollbars, and a status bar, and has an About box. Your application will not register any document templates, and it will not contain a document class.

Note that your generated application has a view class, CChildView, derived from CWnd. MFC creates and positions one instance of the view class within the frame windows created by your application. MFC still enforces using a view window, because it simplifies positioning and managing the application's content. You can add painting code to the OnPaint member of this class. Your code should add scrollbars to the view rather than to the frame.

Because the document/view architecture provided by MFC is responsible for implementing many of an application's basic features, its absence in your project means that you are responsible for implementing many important features of your application:

  • As provided by AppWizard, the menu for your application contains only New and Exit commands on the File menu. The generated menu resource doesn't have an Edit menu and will not support an MRU list.

  • You must add handler functions and implementations for any commands that your application will support, including Open and Save on the File menu. MFC normally provides code to support these features, but that support is tightly bound to the document/view architecture.

  • The toolbar for your application, if you requested one, will be minimal.

It is strongly recommended that you use the MFC AppWizard to create applications without the document/view architecture, because the AppWizard guarantees a correct MFC architecture. However, if you must avoid using the AppWizard, here are several approaches for bypassing the document/view architecture in your code:

  • Treat the document as an unused appendage and implement your data management code in the view class, as suggested above. Overhead for the document is relatively low. A single CDocument object incurs a small amount of overhead by itself, plus the small overhead of CDocument's base classes, CCmdTarget and CObject. Both of the latter classes are small.

    Declared in CDocument:

    • Two CString objects.

    • Three BOOLs.

    • One CDocTemplate pointer.

    • One CPtrList object, which contains a list of the document's views.

    Additionally, the document requires the amount of time to create the document object, its view objects, a frame window, and a document template object.

  • Treat both the document and view as unused appendages. Put your data management and drawing code in the frame window rather than the view. This approach is closer to the C-language programming model.

  • Override the parts of the MFC framework that create the document and view to eliminate creating them at all. The document creation process begins with a call to CWinApp::AddDocTemplate. Eliminate that call from your application class's InitInstance member function and, instead, create a frame window in InitInstance yourself. Put your data management code in your frame window class. The document/view creation process is illustrated in Document/View Creation. This is more work and requires a deeper understanding of the framework, but it frees you entirely of the document/view overhead.

The article MFC: Using Database Classes Without Documents and Views gives more concrete examples of document/view alternatives in the context of database applications.


Using Documents

Home | Overview | How Do I | Sample | Tutorial

Working together, documents and views:

  • Contain, manage, and display your application-specific data.

  • Provide an interface consisting of document data variables for manipulating the data.

  • Participate in writing and reading files.

  • Participate in printing.

  • Handle most of your application's commands and messages.

The document is particularly involved in managing data. Store your data, normally, in document class member variables. The view uses these variables to access the data for display and update. The document's default serialization mechanism manages reading and writing the data to and from files. Documents can also handle commands (but not Windows messages other than WM_COMMAND).

What do you want to know more about?

  • Deriving a document class from CDocument

  • Managing data with document data variables

  • Serializing data to and from files

  • Bypassing the serialization mechanism

  • Handling commands in the document

  • Member functions to override

  • The OnNewDocument member function

  • The DeleteContents member function


Deriving a Document Class from CDocument

Home | Overview | How Do I | Sample | Tutorial

Documents contain and manage your application's data. To use the AppWizard-supplied document class, you must do the following:

  • Derive a class from CDocument for each type of document.

  • Add member variables to store each document's data.

  • Override CDocument's Serialize member function in your document class. Serialize writes and reads the document's data to and from disk.

Other Document Functions Often Overridden

You may also want to override other CDocument member functions. In particular, you will often need to override OnNewDocument and OnOpenDocument to initialize the document's data members and DeleteContents to destroy dynamically allocated data. For information about overridable members, see class CDocument in the Class Library Reference.


Managing Data with Document Data Variables

Home | Overview | How Do I | Sample | Tutorial

Implement your document's data as member variables of your document class. For example, the Scribble tutorial program declares a data member of type CObList — a linked list that stores pointers to CObject objects. This list is used to store arrays of points that make up a freehand line drawing.

How you implement your document's member data depends on the nature of your application. To help you out, MFC supplies a group of "collection classes" — arrays, lists, and maps (dictionaries), including collections based on C++ templates — along with classes that encapsulate a variety of common data types such as CString, CRect, CPoint, CSize, and CTime. For more information about these classes, see the Class Library Overview in the Class Library Reference.

When you define your document's member data, you will usually add member functions to the document class to set and get data items and perform other useful operations on them.

Your views access the document object by using the view's pointer to the document, installed in the view at creation time. You can retrieve this pointer in a view's member functions by calling the CView member function GetDocument. Be sure to cast this pointer to your own document type. Then you can access public document members through the pointer.

If frequent data transfer requires direct access, or you wish to use the nonpublic members of the document class, you may want to make your view class a friend (in C++ terms) of the document class.


Serializing Data to and from Files

Home | Overview | How Do I | Sample | Tutorial

The basic idea of persistence is that an object should be able to write its current state, indicated by the values of its member variables, to persistent storage. Later, the object can be re-created by reading, or "deserializing," the object's state from persistent storage. A key point here is that the object itself is responsible for reading and writing its own state. Thus, for a class to be persistent, it must implement the basic serialization operations.

The framework provides a default implementation for saving documents to disk files in response to the Save and Save As commands on the File menu and for loading documents from disk files in response to the Open command. With very little work, you can implement a document's ability to write and read its data to and from a file. The main thing you must do is override the Serialize member function in your document class.

AppWizard places a skeletal override of the CDocument member function Serialize in the document class it creates for you. After you have implemented your application's member variables, you can fill in your Serialize override with code that sends the data to an "archive object" connected to a file. A CArchive object is similar to the cin and cout input/output objects from the C++ iostream library. However, CArchive writes and reads binary format, not formatted text.

What do you want to know more about?

  • Serialization

  • The document's role in serialization

  • The data's role in serialization

  • Bypassing the serialization mechanism

The Document's Role in Serialization

The framework responds automatically to the File menu's Open, Save, and Save As commands by calling the document's Serialize member function if it is implemented. An ID_FILE_OPEN command, for example, calls a handler function in the application object. During this process, the user sees and responds to the File Open dialog box and the framework obtains the filename the user chooses. The framework creates a CArchive object set up for loading data into the document and passes the archive to Serialize. The framework has already opened the file. The code in your document's Serialize member function reads the data in through the archive, reconstructing data objects as needed. For more information about serialization, see the article Serialization (Object Persistence)

The Data's Role in Serialization

In general, class-type data should be able to serialize itself. That is, when you pass an object to an archive, the object should know how to write itself to the archive and how to read itself from the archive. MFC provides support for making classes serializable in this way. If you design a class to define a data type and you intend to serialize data of that type, design for serialization.


Bypassing the Serialization Mechanism

Home | Overview | How Do I | Sample | Tutorial

As you have seen, the framework provides a default way to read and write data to and from files. Serializing through an archive object suits the needs of a great many applications. Such an application reads a file entirely into memory, lets the user update the file, and then writes the updated version to disk again.

However, some applications operate on data very differently, and for these applications serialization through an archive is not suitable. Examples include database programs, programs that edit only parts of large files, programs that write text-only files, and programs that share data files.

In these cases, you can override the Serialize function in a different way to mediate file actions through a CFile object rather than a CArchive object.

You can use the Open, Read, Write, Close, and Seek member functions of class CFile to open a file, move the file pointer (seek) to a specific point in the file, read a record (a specified number of bytes) at that point, let the user update the record, then seek to the same point again and write the record back to the file. The framework will open the file for you, and you can use the GetFile member function of class CArchive to obtain a pointer to the CFile object. For even more sophisticated and flexible use, you can override the OnOpenDocument and OnSaveDocument member functions of class CWinApp. For more information, see class CFile in the Class Library Reference.

In this scenario, your Serialize override does nothing, unless, for example, you want to have it read and write a file header to keep it up to date when the document closes.

For an example of such nonarchived processing, see the MFC Advanced Concepts sample CHKBOOK.


Handling Commands in the Document

Home | Overview | How Do I | Sample | Tutorial

Your document class may also handle certain commands generated by menu items, toolbar buttons, or accelerator keys. By default, CDocument handles the Save and Save As commands on the File menu, using serialization. Other commands that affect the data may also be handled by member functions of your document. For example, in the Scribble tutorial program, class CScribDoc provides a handler for the Edit Clear All command, which deletes all of the data currently stored in the document. Documents can have message maps, but unlike views, documents cannot handle standard Windows messages — only WM_COMMAND messages, or "commands."


Using Views

Home | Overview | How Do I | Sample | Tutorial

The view's responsibilities are to display the document's data graphically to the user and to accept and interpret user input as operations on the document. Your tasks in writing your view class are to:

  • Write your view class's OnDraw member function, which renders the document's data.

  • Connect appropriate Windows messages and user-interface objects such as menu items to message-handler member functions in the view class.

  • Implement those handlers to interpret user input.

In addition, you may need to override other CView member functions in your derived view class. In particular, you may want to override OnInitialUpdate to perform special initialization for the view and OnUpdate to do any special processing needed just before the view redraws itself. For multipage documents, you also must override OnPreparePrinting to initialize the Print dialog box with the number of pages to print and other information. For more information on overriding CView member functions, see class CView in the Class Library Reference.

What do you want to know more about?

  • Derived view classes available in MFC

  • Views available from AppWizard

  • Drawing in a view

  • Interpreting user input through a view

  • The role of the view in printing

  • Scrolling and scaling views

  • Initializing and cleaning up views


Derived View Classes

Home | Overview | How Do I | Sample | Tutorial

The following table shows MFC's view classes and their relationships to one another. The capabilities of your view class depend on the MFC view class from which it derives.

View Classes

Class | Description
CView | Base class of all views.
CCtrlView | Base class of CTreeView, CListView, CEditView, and CRichEditView. These classes let you use document/view architecture with the indicated Windows common controls.
CEditView | A simple view based on the Windows edit box control. Allows entering and editing text and can be used as the basis for a simple text editor application. See also CRichEditView.
CRichEditView | A view containing a CRichEditCtrl object. This class is analogous to CEditView, but unlike CEditView, CRichEditView handles formatted text.
CListView | A view containing a CListCtrl object.
CTreeView | A view containing a CTreeCtrl object, for views that resemble the Workspace window in Visual C++.
CScrollView | Base class of CFormView, CRecordView, and CDaoRecordView. Implements scrolling the view's contents.
CFormView | A form view, a view that contains controls. A forms-based application provides one or more such form interfaces, as do the AppWizards.
CHtmlView | A Web browser view with which the application's user can browse sites on the World Wide Web, as well as folders in the local file system and on a network. The Web browser view can also work as an Active document container.
CRecordView | A form view that displays ODBC database records in controls. If you select ODBC support in your project, the view's base class is CRecordView. The view is connected to a CRowset object.
CDaoRecordView | A form view that displays DAO database records in controls. If you select DAO support in your project, the view's base class is CDaoRecordView. The view is connected to a CDaoRecordset object.
COleDBRecordView | A form view that displays OLE DB records in controls. If you select OLE DB support in your project, the view's base class is COleDBRecordView. The view is connected to a CRowset object. Note that COleDBRecordView is not currently supported by ClassWizard, nor by the New Class nor New Form commands on the Insert menu.

Note As of MFC version 4.0, CEditView is derived from CCtrlView.

To use these classes in your application, derive the application's view classes from them. For related information, see Scrolling and Scaling Views. For more information on the database classes, see Databases: Overview.


Views Available from AppWizard

Home | Overview | How Do I | Sample | Tutorial

All view classes listed in the table in Derived View Classes, except CCtrlView and CDaoRecordView, are available in the MFC AppWizard. In step 6 of the AppWizard, select the application's view class, then in the Base class drop-down menu, select a base class for that view.

Three common styles of applications, based on various view classes, are available from AppWizard:

  • Forms-based applications

  • Web browser-style applications

  • Explorer-style application

In addition to these types of views, the MFC AppWizard also provides the option to create an application without document/view architecture. In step 1 of the MFC AppWizard, clear the Document/View architecture support check box. For more information, see Alternatives to the Document/View Architecture.


Forms-Based Applications

Home | Overview | How Do I | Sample | Tutorial

CFormView is the base class for form views. A form view is essentially a view that contains controls. A forms-based application lets the user create and use one or more forms within the application, as do the AppWizards and other dialog-based applications. The view class of a forms-based application is based on one of the form-style classes such as CFormView, CRecordView, CDaoRecordView, or CDialog.

To create a forms-based application, use one of the following procedures:

  • Create an application using MFC AppWizard. Either create a dialog-based application or select a form-style class as the view's base class.

  • Insert a new form into an existing MFC application. Even if your application did not initially support forms, Visual C++ will add this support when you insert a new form.

The procedures above are preferred for creating forms-based applications. Because these procedures automatically and correctly implement the forms-based architecture, you should never have to do so by hand. However, if you need to create a forms-based application without using the AppWizard or the New Form command on the Insert menu, the following steps are provided for your information. These steps are the same as those that the MFC AppWizard performs in creating a CFormView-based application.

Note The following steps do not apply to CDialog-based applications. For dialog-based applications, the MFC AppWizard creates a CDialog-based class and a dialog resource with appropriate styles as described in step 1 below.

  1. Creating a view based on CFormView is similar to creating a dialog box. Use the dialog editor to design the dialog box.

  2. In the Styles and More Styles property pages, set the following properties:
    • In the Style box, select Child (WS_CHILD on).

    • In the Border box, select None (WS_BORDER off).

    • Clear the Visible check box (WS_VISIBLE off).

    • Clear the Titlebar check box (WS_CAPTION off).

    These steps are necessary because a form view is not a true dialog box. For more information about creating a dialog-box resource, see Dialog Editor.

  3. Create a view class.

    With your dialog template open, run ClassWizard and choose CFormView as the class type when you are filling in the Add Class dialog box. ClassWizard creates a CFormView-derived class and connects it to the dialog template you just designed. This connection is established in the constructor for your class; ClassWizard generates a call to the base-class constructor, CFormView::CFormView, and passes the resource ID of your dialog template. For example:

    CMyFormView::CMyFormView()
    : CFormView( CMyFormView::IDD )
{
    //{{AFX_DATA_INIT( CMyFormView )
    // NOTE: the ClassWizard will add member
    // initialization here
    //}}AFX_DATA_INIT

    // Other construction code, such as data initialization
}

    Note If you choose not to use ClassWizard, you must define the appropriate ID you supply to the CFormView constructor (that is, CMyFormView::IDD is not predefined). ClassWizard declares IDD as an enum value in the class it creates for you.

    If you want to define member variables in your view class that correspond to the controls in your form view, use the Add Variables button on the Member Variables tab of the ClassWizard. This allows you to use the dialog data exchange (DDX) mechanism. If you want to define message handlers for control-notification messages, use the Add Function button on the Message Maps tab of the ClassWizard. For more information see Using ClassWizard in the Visual C++ Programmer's Guide.

  4. Override the OnUpdate member function.

    The OnUpdate member function is defined by CView and is called to update the form view’s appearance. Override this function to update the member variables in your view class with the appropriate values from the current document. Then, if you are using DDX, use the UpdateData member function (defined by CWnd) with an argument of FALSE to update the controls in your form view.

    The OnInitialUpdate member function (also defined by CView) is called to perform one-time initialization of the view. CFormView overrides this function to use DDX to set the initial values of the controls you have mapped using ClassWizard. Override OnInitialUpdate if you want to perform custom initialization.

  5. Implement a member function to move data from your view to your document.

    This member function is typically a message handler for a control-notification message or for a menu command. If you are using DDX, call the UpdateData member function to update the member variables in your view class. Then move their values to the document associated with the form view.

  6. Override the OnPrint member function (optional).

    The OnPrint member function is defined by CView and prints the view. By default, printing and print preview are not supported by the CFormView class. To add printing support, override the OnPrint function in your derived class.

  7. Associate your view class with a document class and a frame-window class using a document template.

Unlike ordinary views, form views do not require you to override the OnDraw member function defined by CView. This is because controls are able to paint themselves. Only if you want to customize the display of your form view (for example, to provide a background for your view) should you override OnDraw. If you do so, be careful that your updating does not conflict with the updating done by the controls.

Form views support scrolling, as needed, using functionality provided by CScrollView. If your view contains controls that are derived from (or instances of) CSliderCtrl or CSpinButtonCtrl and you have message handlers for WM_HSCROLL and WM_VSCROLL, you should write code that calls the proper routines. The code example below calls CWnd::OnHScroll if a WM_HSCROLL message is sent by either a spin button or slider control.

void CMyFormView::OnHScroll( UINT nSBCode, UINT nPos, CScrollBar* pScrollBar )
{
    if ( pScrollBar->IsKindOf( RUNTIME_CLASS( CScrollBar ) ))
    {
        CFormView::OnHScroll( nSBCode, nPos, pScrollBar );
    }
    else if ( pScrollBar->IsKindOf( RUNTIME_CLASS( CSliderCtrl ) ))
    {
        CWnd::OnHScroll( nSBCode, nPos, pScrollBar );
    }
    else if ( pScrollBar->IsKindOf( RUNTIME_CLASS( CSpinButtonCtrl ) ))
    {
        CWnd::OnHScroll( nSBCode, nPos, pScrollBar );
    }
}

If the view becomes smaller than the dialog template, scroll bars appear automatically. Views derived from CFormView support only the MM_TEXT mapping mode.

If you are not using DDX, use the CWnd dialog functions to move data between the member variables in your view class and the controls in your form view. For more information about DDX, see Defining Member Variables for DDX.

What do you want to know more about?

  • CFormView

  • Derived view classes

  • Creating a forms-based application

  • Inserting a form into an MFC application


Web Browser-Style Applications

Home | Overview | How Do I | Sample | Tutorial

A Web browser-style application can access information from the Internet (such as HTML or Active documents) or an intranet, as well as folders in the local file system and on a network. By deriving the application's view class from CHtmlView, you effectively make the application a Web browser by providing the view with the WebBrowser control.

The WebBrowser control supports Web browsing through hyperlinks and Uniform Resource Locator (URL) navigation. The control maintains a history list that allows the user to browse forward and backward through previously-browsed sites, folders, and documents. The control directly handles the navigation, hyperlinks, history lists, favorites, and security. Applications can also use the WebBrowser control as an Active document container to host Active Documents. Thus, richly formatted documents such as Microsoft Excel spreadsheets or Word documents can be opened and edited in-place from within the WebBrowser control. The WebBrowser control is also an ActiveX control container that can host any ActiveX control.

The WebBrowser ActiveX control (and therefore CHtmlView) is available only to programs running under Windows 95 and Windows NT versions 3.51 and later, in which Internet Explorer 4.0 (or later) has been installed.

Because CHtmlView simply implements the Microsoft Web browser control, its support for printing is not like other CView-derived classes. Rather, the WebBrowser control implements the printer user interface and printing. As a result, CHtmlView does not support print preview, and the framework does not provide for other printing support functions, for example, CView::OnPreparePrinting, CView::OnBeginPrinting, and CView::OnEndPrinting, that are available in other MFC applications.

To create a Web browser-style application, use the MFC AppWizard. In step 6, select CHtmlView as the view's base class. This is discussed in detail in Creating a Web Browser-Style Application.

What do you want to know more about?

  • Overview: HTML Resource

  • CHtmlView

  • MFC Sample MFCIE

  • IWebBrowser2, in the Platform SDK


Explorer-Style Applications

Home | Overview | How Do I | Sample | Tutorial

An Explorer-style application has the same user interface as that of Windows Explorer. The application has a vertically-divided client area that contains left and right panes. The left pane displays a tree control, while the right pane shows detailed information pertinent to the current selection in the left pane.

The contents of the panes depend on the application. In a file-system browser, the left pane shows a hierarchical view of directories or machines, or machine groups, while the right pane displays individual files or machines and details about them. The contents do not necessarily have to be files. They could be email messages, error reports, or other items in a database.

It is strongly recommended that you create Explorer-style applications using the MFC AppWizard. In step 5, under What style of project would you like? select the Windows Explorer radio button. This is discussed in detail in Creating an Explorer-Style Application.

The AppWizard creates the following classes for you:

  • The CLeftView class defines the left pane of the client area. It is always derived from CTreeView.

  • The CExploreView class defines the right pane of the client area. By default it is derived from CListView, but can be another type of view depending on the class you specify from the Base class drop-down menu in step 6 of the AppWizard.

  • The generated application can have either a single or multiple document interface. Each frame window the application creates is horizontally split using CSplitterWnd. Coding this application type is similar to coding a normal MFC application that uses a splitter, except that this type of application has separate control views within each splitter pane.

What do you want to know more about?

  • Creating an explorer-style application

  • Splitter windows

  • Derived view classes


Drawing in a View

Home | Overview | How Do I | Sample | Tutorial

Nearly all drawing in your application occurs in the view's OnDraw member function, which you must override in your view class. (The exception is mouse drawing, discussed in Interpreting User Input Through a View.) Your OnDraw override:

  1. Gets data by calling the document member functions you provide.

  2. Displays the data by calling member functions of a device-context object that the framework passes to OnDraw.

When a document's data changes in some way, the view must be redrawn to reflect the changes. Typically, this happens when the user makes a change through a view on the document. In this case, the view calls the document's UpdateAllViews member function to notify all views on the same document to update themselves. UpdateAllViews calls each view's OnUpdate member function. The default implementation of OnUpdate invalidates the view's entire client area. You can override it to invalidate only those regions of the client area that map to the modified portions of the document.

The UpdateAllViews member function of class CDocument and the OnUpdate member function of class CView let you pass information describing what parts of the document were modified. This "hint" mechanism lets you limit the area that the view must redraw. OnUpdate takes two "hint" arguments. The first, lHint, of type LPARAM, lets you pass any data you like, while the second, pHint, of type CObject*, lets you pass a pointer to any object derived from CObject.

When a view becomes invalid, Windows sends it a WM_PAINT message. The view's OnPaint handler function responds to the message by creating a device-context object of class CPaintDC and calls your view's OnDraw member function. You do not normally have to write an overriding OnPaint handler function.

A device context is a Windows data structure that contains information about the drawing attributes of a device such as a display or a printer. All drawing calls are made through a device-context object. For drawing on the screen, OnDraw is passed a CPaintDC object. For drawing on a printer, it is passed a CDC object set up for the current printer.

Your code for drawing in the view first retrieves a pointer to the document, then makes drawing calls through the device context. The following simple OnDraw example illustrates the process:

void CMyView::OnDraw( CDC* pDC )
{
    CMyDoc* pDoc = GetDocument();
    CString s = pDoc->GetData();   // Returns a CString
    CRect rect;

    GetClientRect( &rect );
    pDC->SetTextAlign( TA_BASELINE | TA_CENTER );
    pDC->TextOut( rect.right / 2, rect.bottom / 2,
                  s, s.GetLength() );
}

In this example, you would define the GetData function as a member of your derived document class.

The example prints whatever string it gets from the document, centered in the view. If the OnDraw call is for screen drawing, the CDC object passed in pDC is a CPaintDC whose constructor has already called BeginPaint. Calls to drawing functions are made through the device-context pointer. For information about device contexts and drawing calls, see class CDC in the Class Library Reference and Working with Window Objects.

For more examples of how to write OnDraw, see the MFC Samples.


Interpreting User Input Through a View

Home | Overview | How Do I | Sample | Tutorial

Other member functions of the view handle and interpret all user input. You will usually define message-handler member functions in your view class to process:

  • Windows messages generated by mouse and keyboard actions.

  • Commands from menus, toolbar buttons, and accelerator keys.

These message-handler member functions interpret the following actions as data input, selection, or editing, including moving data to and from the Clipboard:

  • Mouse movements and clicks, drags, and double-clicks

  • Keystrokes

  • Menu commands

Which Windows messages your view handles depends on your application's needs.

Message Handling and Mapping Topics explains how to assign menu items and other user-interface objects to commands and how to bind the commands to handler functions with ClassWizard or WizardBar. Message Handling and Mapping Topics also explains how MFC routes commands and sends standard Windows messages to the objects that contain handlers for them.

For example, your application might need to implement direct mouse drawing in the view. The Scribble tutorial example shows how to handle the WM_LBUTTONDOWN, WM_MOUSEMOVE, and WM_LBUTTONUP messages respectively to begin, continue, and end the drawing of a line segment. On the other hand, you might sometimes need to interpret a mouse click in your view as a selection. Your view's OnLButtonDown handler function would determine whether the user was drawing or selecting. If selecting, the handler would determine whether the click was within the bounds of some object in the view and, if so, alter the display to show the object as selected.

Your view might also handle certain menu commands, such as those from the Edit menu to cut, copy, paste, or delete selected data using the Clipboard. Such a handler would call some of the Clipboard-related member functions of class CWnd to transfer a selected data item to or from the Clipboard.


The Role of the View in Printing

Home | Overview | How Do I | Sample | Tutorial

Your view also plays two important roles in printing its associated document.

The view:

  • Uses the same OnDraw code to draw on the printer as to draw on the screen.

  • Manages dividing the document into pages for printing.

For more information about printing and about the view's role in printing, see Printing and Print Preview: Overview.


Scrolling and Scaling Views

Home | Overview | How Do I | Sample | Tutorial

MFC supports views that scroll and views that are automatically scaled to the size of the frame window that displays them. Class CScrollView supports both kinds of views.

For more information about scrolling and scaling, see class CScrollView in the Class Library Reference. For a scrolling example, see Enhancing Views, in Tutorials.

What do you want to know more about?

  • Scrolling a view

  • Scaling a view

  • View coordinates

Scrolling a View

Frequently the size of a document is greater than the size its view can display. This may occur because the document's data increases or the user shrinks the window that frames the view. In such cases, the view must support scrolling.

Any view can handle scroll-bar messages in its OnHScroll and OnVScroll member functions. You can either implement scroll-bar message handling in these functions, doing all the work yourself, or you can use the CScrollView class to handle scrolling for you.

CScrollView does the following:

  • Manages window and viewport sizes and mapping modes

  • Scrolls automatically in response to scroll-bar messages

You can specify how much to scroll for a "page" (when the user clicks in a scroll-bar shaft) and a "line" (when the user clicks in a scroll arrow). Plan these values to suit the nature of your view. For example, you might want to scroll in 1-pixel increments for a graphics view but in increments based on the line height in text documents.

Scaling a View

When you want the view to automatically fit the size of its frame window, you can use CScrollView for scaling instead of scrolling. The logical view is stretched or shrunk to fit the window's client area exactly. A scaled view has no scroll bars.


Multiple Document Types, Views, and Frame Windows

Home | Overview | How Do I | Sample | Tutorial

The standard relationship among a document, its view, and its frame window is described in Document/View Creation. Many applications support a single document type (but possibly multiple open documents of that type) with a single view on the document and only one frame window per document. But some applications may need to alter one or more of those defaults.

What do you want to know more about?

  • Multiple document types

  • Multiple views

  • Multiple frame windows

  • Splitter windows

Multiple Document Types

AppWizard creates a single document class for you. In some cases, though, you may need to support more than one document type. For example, your application may need worksheet and chart documents. Each document type is represented by its own document class and probably by its own view class as well. When the user chooses the File New command, the framework displays a dialog box that lists the supported document types. Then it creates a document of the type that the user chooses. Each document type is managed by its own document-template object.

To create extra document classes, use the Add Class button in the ClassWizard dialog box. Choose CDocument as the Class Type to derive from and supply the requested document information. Then implement the new class's data.

To let the framework know about your extra document class, you must add a second call to AddDocTemplate in your application class's InitInstance override. For more information, see Document Templates.

Multiple Views

Many documents require only a single view, but it is possible to support more than one view of a single document. To help you implement multiple views, a document object keeps a list of its views, provides member functions for adding and removing views, and supplies the UpdateAllViews member function for letting multiple views know when the document's data has changed.

MFC supports three common user interfaces requiring multiple views on the same document. These models are:

  • View objects of the same class, each in a separate MDI document frame window.

    You might want to support creating a second frame window on a document. The user could choose a New Window command to open a second frame with a view of the same document and then use the two frames to view different portions of the document simultaneously. The framework supports the New Window command on the Window menu for MDI applications by duplicating the initial frame window and view attached to the document.

  • View objects of the same class in the same document frame window.

    Splitter windows split the view space of a single document window into multiple separate views of the document. The framework creates multiple view objects from the same view class. For more information, see Splitter Windows.

  • View objects of different classes in a single frame window.

    In this model, a variation of the splitter window, multiple views share a single frame window. The views are constructed from different classes, each view providing a different way to view the same document. For example, one view might show a word-processing document in normal mode while the other view shows it in outline mode. A splitter control allows the user to adjust the relative sizes of the views.

The following figure, divided into parts a, b, and c, shows the three user-interface models in the order presented above.

Multiple-View User Interfaces

The framework provides these models by implementing the New Window command and by providing class CSplitterWnd, as discussed in Splitter Windows. You can implement other models using these as your starting point. For sample programs that illustrate different configurations of views, frame windows, and splitters, see MFC Samples under Samples.

For more information about UpdateAllViews, see class CView in the Class Library Reference and Enhancing Views in Tutorials.

Multiple Frame Windows

You can use the New Window command to create a second frame window on the same document. For more information, see the first model in the figure Multiple-View User Interfaces.

Splitter Windows

In a splitter window, the window is, or can be, split into two or more scrollable panes. A splitter control (or "split box") in the window frame next to the scroll bars allows the user to adjust the relative sizes of the panes. Each pane is a view on the same document. In "dynamic" splitters, the views are of the same class, as shown in part b of the figure Multiple-View User Interfaces. In "static" splitters, the views can be of different classes. Splitter windows of both kinds are supported by class CSplitterWnd.

Dynamic splitter windows, with views of the same class, allow the user to split a window into multiple panes at will and then scroll different panes to see different parts of the document. The user can also unsplit the window to remove the additional views. The splitter windows added to the Scribble application in Enhancing Views in Tutorials are an example. That topic describes the technique for creating dynamic splitter windows. A dynamic splitter window is shown in part b of the figure Multiple-View User Interfaces.

Static splitter windows, with views of different classes, start with the window split into multiple panes, each with a different purpose. For example, in the Visual C++ bitmap editor, the image window shows two panes side by side. The left-hand pane displays a life-sized image of the bitmap. The right-hand pane displays a zoomed or magnified image of the same bitmap. The panes are separated by a "splitter bar" that the user can drag to change the relative sizes of the panes. A static splitter window is shown in part c of the figure Multiple-View User Interfaces.

For more information, see class CSplitterWnd in the Class Library Reference and MFC Samples under Samples.


Initializing and Cleaning Up Documents and Views

Home | Overview | How Do I | Sample | Tutorial

Use the following guidelines for initializing and cleaning up after your documents and views:

  • The MFC framework initializes documents and views; you initialize any data you add to them.

  • The framework cleans up as documents and views close; you must deallocate any memory that you allocated on the heap from within the member functions of those documents and views.

Note Recall that initialization for the whole application is best done in your override of the InitInstance member function of class CWinApp, and cleanup for the whole application is best done in your override of the CWinApp member function ExitInstance.

The life cycle of a document (and its frame window and view or views) in an MDI application is as follows:

  1. During dynamic creation, the document constructor is called.

  2. For each new document, the document's OnNewDocument or OnOpenDocument is called.

  3. The user interacts with the document throughout its lifetime. Typically this happens as the user works on document data through the view, selecting and editing the data. The view passes changes on to the document for storage and updating other views. During this time both the document and the view might handle commands.

  4. The framework calls DeleteContents to delete data specific to a document.

  5. The document's destructor is called.

In an SDI application, step 1 is performed once, when the document is first created. Then steps 2 through 4 are performed repeatedly each time a new document is opened. The new document reuses the existing document object. Finally, step 5 is performed when the application ends.


Initializing Documents and Views

Home | Overview | How Do I | Sample | Tutorial

Documents are created in two different ways, so your document class must support both ways. First, the user can create a new, empty document with the File New command. In that case, initialize the document in your override of the OnNewDocument member function of class CDocument. Second, the user can use the Open command on the File menu to create a new document whose contents are read from a file. In that case, initialize the document in your override of the OnOpenDocument member function of class CDocument. If both initializations are the same, you can call a common member function from both overrides, or OnOpenDocument can call OnNewDocument to initialize a clean document and then finish the open operation.

Views are created after their documents are created. The best time to initialize a view is after the framework has finished creating the document, frame window, and view. You can initialize your view by overriding the OnInitialUpdate member function of CView. If you need to reinitialize or adjust anything each time the document changes, you can override OnUpdate.


Cleaning Up Documents and Views

Home | Overview | How Do I | Sample | Tutorial

When a document is closing, the framework first calls its DeleteContents member function. If you allocated any memory on the heap during the course of the document's operation, DeleteContents is the best place to deallocate it.

Note You should not deallocate document data in the document's destructor. In the case of an SDI application, the document object might be reused.

You can override a view's destructor to deallocate any memory you allocated on the heap.


Form Topics

Home

You can add forms to any Visual C++ application that supports the MFC libraries, including a forms-based application (one whose view class is derived from CFormView). If you didn't initially create your application to support forms, Visual C++ will add this support for you when you insert a new form. In an SDI or MDI application, which implements the default document/view architecture, when the user chooses the New command (by default, on the File menu), Visual C++ prompts the user to choose from the available forms.

With an SDI application, when the user chooses the New command, the current instance of the form closes and the user can open another instance of that form or any other available form. In an MDI application, the current instance of the form continues to run when the user chooses the New command.

Note You can insert a form into a dialog-based application (one whose dialog class is based on CDialog and one in which no view class is implemented). However, without the document/view architecture, Visual C++ does not automatically implement the File|New functionality. You must create a way for the user to view additional forms, such as by implementing a tabbed dialog box with various property pages.

When you insert a new form into your application, Visual C++ does the following:

  • Creates a class based on one of the form-style classes that you choose (CFormView, CRecordView, CDaoRecordView, or CDialog).

    For programs without a document/view architecture (this includes dialog-based applications and ATL programs with MFC support), the initial base class is always CDialog.

  • Creates a dialog resource with appropriate styles (or you can use an existing dialog resource that has not yet been associated with a class).

    If you choose an existing dialog resource, you may need to set these styles by using the Properties page for the dialog box. Styles for a dialog box must include:

    WS_CHILD=On

    WS_BORDER=Off

    WS_VISIBLE=Off

    WS_CAPTION=Off

For applications based on the document/view architecture, the New Form command also:

  • Creates a CDocument-based class with a name based on the first three letters of the form class (skipping the leading "C").

    You can choose, instead of having a new class created, to use any existing CDocument-based class in your project.

  • Generates a document template (derived from CDocument) with string, menu, and icon resources.

    You can also create a new class on which to base the template.

  • Adds a call to AddDocumentTemplate in your app's InitInstance code.

    Visual C++ adds this code for each new form you create, which adds the form to the list of available forms when the user chooses the New command. This code includes the form's associated resource ID, and the names of the associated document, view, and frame classes that together make up the new form object.

    Document templates serve as the connection between documents, frame windows, and views. For a single document, you can create many templates.

What do you want to do?

Create a forms-based application

Insert a form into a project


Inserting a Form into a Project

Home

Forms provide a convenient container for controls. You can easily insert an MFC-based form into your application, so long as the application supports the MFC libraries.

forms, inserting into a project; forms, adding to a project; inserting forms; Insert New dialog box; forms, Insert New Form dialog box

To insert a form into your project

  1. From ClassView, select the project to which you want to add the form, and click the right mouse button.

  2. From the shortcut menu, choose New Form.

    If the New Form command is not available, your project may be based on the ActiveX Template libraries (ATL). To add a form to an ATL project, you must specify MFC support when first creating the project.

  3. In the New Form dialog box, type a name for the form.

    The remaining fields under Form Information are automatically generated from the form name.

  4. Use the Automation area to specify whether the form will support automation.

  5. Use the Document Template Information fields to specify information about the document associated with the form.

  6. Click Change if you want to change the generated file extension, or other aspects of the template such as the name displayed in the Save as Type dialog box, the New dialog box, and so forth.

Visual C++ adds the form to your application, opening it inside the Dialog editor so that you can begin adding controls and working on its overall design.

You may want to perform the following additional steps (not applicable for dialog-based applications):

  1. Override the OnUpdate member function.

  2. Implement a member function to move data from your view to your document.

  3. Create an OnPrint member function.

For more information, see CFormView.


Help Topics: Context-Sensitive Help for Your Programs

Home | Overview | How Do I | Sample | Tutorial

This group of articles describes support provided by the Microsoft Foundation Class Library (MFC) for context-sensitive Windows Help for your applications.

Applications written for Windows usually provide context-sensitive Help, allowing the user to get help on a particular window, dialog box, command, or toolbar button. MFC makes it simple to add context-sensitive Help to your application.

The user can access Help in the following ways:

  • Pressing the F1 key

    The user can press the F1 key from an active window, dialog box, or message box, or with a menu item or toolbar button selected, to invoke a Help topic relevant to the selected item. For menu items, help is summoned for the item currently highlighted.

    Note You can define a key other than F1 for Help, but it is common among Windows applications to use F1.

  • Entering Help mode

    From within an active application, the user can press SHIFT+F1 or click on the Help toolbar button to put the application into “Help mode.”

    In Help mode, the mouse cursor changes to an arrow with a question mark. While the application is in this mode, the user can click any window, dialog box, message box, menu item, or toolbar button to summon help specific to the item. Help mode ends when Help is displayed. Pressing ESC or switching away from the application and back also ends Help mode.

  • Using the Help menu

    Most applications provide help support through one or more menu items. For instance, most Windows applications include a Help menu item that invokes the application’s Help file when chosen. Additional items on the Help menu might, for example, display a Search dialog.

The following articles present an overview of the MFC help subsystem:

  • Help: Components of Help

  • Help: Support Tools

The following additional articles explain MFC help support in more detail:

  • Help: F1 and SHIFT+F1 Help

  • Help: OLE Support for Help

  • Help: Message-Map Support

  • Help: The Help Project File

  • Help: The MakeHm Tool

  • Help: CPropertySheet and CPropertyPage

  • Help: Authoring Help Topics

  • Help: More Precise Context-Sensitivity

For a detailed example, see Adding Context-Sensitive Help in Tutorials. For additional technical information, see Technical Note 28.


Help: Components of Help

Home | Overview | How Do I | Sample | Tutorial

The help subsystem in the MFC framework has the following components, many of which are supplied by AppWizard when you choose its Context-Sensitive Help option:

  • A Help drop-down menu with several commands. For a new MDI application, there are two copies of this menu: one for an application with no open documents and one for each type of document that uses its own menu structure. AppWizard supplies these menus.

  • Several message-map entries in your CWinApp-derived application class. These entries bind F1 and SHIFT+F1 commands to their respective command handlers. AppWizard supplies these message-map entries.

  • Message handlers for F1 and SHIFT+F1. Class CWinApp supplies these handlers, and AppWizard supplies the message-map entries for them.

  • The CWinApp::WinHelp member function, which calls the Windows Help program, WINHELP.EXE.

  • Additional AppWizard support for help, including several help-related files. The files include skeleton .RTF files that contain help entries for the common elements of the Windows user interface, such as the File and Edit menus. You can edit these files to revise the supplied text and add your own application-specific help information.

  • A mechanism and tool for mapping resource and command IDs in your application to “help contexts” in Windows Help. The MakeHm tool is introduced in Using MakeHm.

What do you want to know more about?

  • The MFC Help implementation

  • Help support tools

  • Kinds of context-sensitive help

  • OLE support for help

  • Message maps and help commands

  • Help for property sheets

  • Authoring help topics

  • Building your help file

  • Implementing more precise context-sensitivity, such as at the control level rather than the dialog box level


Help: Support Tools

Home | Overview | How Do I | Sample | Tutorial

You will use three main tools to develop your application’s Help system: AppWizard, MakeHm, and the Windows Help Compiler. You also need an editor, such as Microsoft Word for Windows, that can edit rich text format (.RTF) files. You can use the Visual C++ bitmap editor to create bitmaps to include in your Help files.

Note You can upgrade your Help Project files to a 4.0 format with the Windows 4.0 Help compiler. This gives you access to the Windows 4.0 Help Workshop, a graphical help authoring environment with many useful features. If you’re planning on porting your applications to other platforms, first ensure that those platforms have a compiler that’s compatible with the 4.0 Help Project file before upgrading.

Choosing the Help Option in AppWizard

AppWizard is your first tool for implementing context-sensitive Help. Check the Context-Sensitive Help checkbox in AppWizard. AppWizard then provides the message-map entries in your CWinApp-derived class that connect the whole help mechanism, adds a menu item to the Help menu, and adds a button to the toolbar resource that the user can press to invoke Help mode.

AppWizard also creates a set of skeletal starter files, as shown in the following table.

AppWizard-Supplied Help Files

File | Description
MakeHelp.bat | A batch file that manages help ID mapping and calls the Help Compiler. Only supplied in Visual C++ 6.0 for compatibility with previous releases. Custom build rules for the .hpj, .cnt and resource.h file replace the functionality of MakeHelp.bat.
HLP\<project>.HPJ | A Windows Help project file that the Windows Help Compiler uses.
HLP\<project>.CNT | A file containing the information needed to create the Help Contents screen.
HLP\*.BMP | Various bitmap files used with the supplied Help files.
HLP\*.RTF | Help files in .RTF format that contain starter help for the application components supplied by the framework.

The MakeHelp.bat file is in your project directory. The .BMP, .RTF, .CNT, and Help project file (.HPJ) are in an HLP subdirectory that AppWizard creates in your project directory.

You can edit these files as described in Help: Authoring Help Topics to fill in application-specific help information.

Using MakeHm

Once you’ve created an AppWizard application with help support, you can build help simply by clicking Build <project> on the Build menu. This command runs invokes the custom build rules on the .hpj, .cnt and resource.h files and create an .HLP file..

If the resource.h file changed, MakeHm runs. MakeHm reads your project’s RESOURCE.H file and creates a help mapping (.HM) file. This .HM file defines help-context IDs corresponding to the resource IDs in your RESOURCE.H file, so that each dialog, menu item, or other resource has a help-context ID associated with it.

Your project’s .HPJ file contains a statement in its [MAP] section that includes your project’s .HM file, as well as the standard .HM file included with MFC. The Help Compiler uses the help-context IDs in these .HM files to determine which Help topic is associated with each dialog, menu item, or other resource.

Whenever you add new resources to your project, you must add new Help topics for those resources to your .RTF files and then recompile your Help file. For more information, see Compiling Your Help Files in Tutorials.

Custom build rules will run the Windows Help Compiler to create the .HLP file if the .hpj file changes. The Help Compiler creates the .HLP file in your application’s main source code directory. If a Debug and/or Release subdirectory already exists, the .HLP file is copied to that subdirectory. This is useful because when you run either the Debug or Release version of your application, it will expect to find the .HLP file in the same directory as the debug or release executable file.

If you add new resources for which you wish to implement help contexts, compile the .HPJ from either the command line or from within the integrated development environment.


Help: F1 and SHIFT+F1 Help

Home | Overview | How Do I | Sample | Tutorial

This article describes the two forms of context-sensitive Windows Help supported by MFC.

F1 Help opens help on a topic associated with the currently selected item in your application. MFC supplies F1 help for windows, dialog boxes, message boxes, menus, and toolbar buttons.

SHIFT+F1 Help invokes a special “Help mode” in which the cursor turns into a Help cursor. The user can then select a visible object in the user interface, such as a menu item, toolbar button, or window. This opens help on a topic that describes the selected item.

F1 Help Support

The framework implements F1 help for windows, dialog boxes, message boxes, menus, and toolbar buttons. If the cursor is over a window, dialog box, or message box when the user presses the F1 key, the framework opens Windows Help for that window. If a menu item is highlighted, the framework opens Windows Help for that menu item. And if a toolbar button has been pressed (but the mouse not released yet), the framework opens Windows Help for that toolbar button when the user presses F1. (With extra work, you can implement F1 help for other things.)

When the user presses the F1 key, the framework processes the keystroke as a help request as follows, using a variation on the normal command routing. Pressing F1 causes a WM_COMMAND message to be sent for the ID_HELP command. If the application supports help, this command is mapped to the OnHelp message handler of class CWinApp and is routed directly there. OnHelp uses the ID of the current frame window or dialog box to determine the appropriate Help topic to display. If no specific Help topic is found, OnHelp displays the default Help topic.

SHIFT+F1 Help Support

If the user presses SHIFT+F1 or clicks on the Help toolbar button at any time that the application is active, the framework puts the application into Help mode and changes the cursor to a Help cursor (arrow + question mark). The next thing the user clicks determines what help context the framework opens in Windows Help.

When the user presses SHIFT+F1 or clicks on the Help toolbar button, the framework routes the command ID_CONTEXT_HELP through the normal command routing. The command is mapped to the CWinApp member function OnContextHelp, which captures the mouse, changes the cursor to a Help cursor, and puts the application into Help mode. The Help cursor is maintained as long as the application is in Help mode but reverts to a normal arrow cursor if it is not over the application that is in Help mode. Activating a different application cancels Help mode in the original application. While in Help mode, the application determines what object the user clicks and calls the CWinApp member function WinHelp with the appropriate context, determined from the object clicked upon. Once an object has been selected, Help mode ends and the cursor is restored to the normal arrow.

Note For information about how context-sensitive Help is managed in OLE applications, see the article Help: OLE Support for Help.

For more information, see Technical Note 28.

See Also Help: Message-Map Support


Help: OLE Support for Help

Home | Overview | How Do I | Sample | Tutorial

This article describes the requirements for Help support in OLE visual editing applications.

For SHIFT+F1 support, some special coordination is required between OLE containers and in-place active servers. When the user chooses to activate SHIFT+F1 Help mode, both applications need to enter the mode. Whichever application first gets the message to enter the mode notifies the other application. Then either application is prepared to respond when the user clicks the mouse on an item for which he or she wants help. Likewise, when the user terminates Help mode, the application that gets the message first notifies the other application. Note that MFC automatically handles this notification process between the container and the in-place server.

Caution Neither the container nor the server can enter SHIFT+F1 help mode unless the other application also supports the mode.

For F1 help support, by contrast, whichever application gets the message when F1 is pressed handles the help request.

See Also Help: Message-Map Support


Help: Message-Map Support

Home | Overview | How Do I | Sample | Tutorial

AppWizard adds a new menu command to the two Help menus: Help Topics. Support for this command and for F1 and SHIFT+F1 help is provided through the message map. Topics covered in this article include:

  • Help commands in the message map

  • About the Help commands

  • Completing your application’s Help

Help Commands in the Message Map

To support the Help Topics menu item, F1 help, and SHIFT+F1 help, AppWizard adds four entries to the message map for your CFrameWnd-derived or CMDIFrameWnd-derived class. This message map is in the MainFrm.cpp file, and the relevant message map entries are located below the // Global help commands comment.

After you run AppWizard, click Context-Sensitive Help. The message map for class CMainFrame will look like the following for an MDI application:

// CMainFrame

BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
   //{{AFX_MSG_MAP(CMainFrame)

   // NOTE - the ClassWizard will add and remove mapping macros here.
   //   DO NOT EDIT what you see in these blocks of generated code !
   ON_WM_CREATE()
   //}}AFX_MSG_MAP
   // Global help commands
   ON_COMMAND(ID_HELP_FINDER, CMDIFrameWnd::OnHelpFinder)
   ON_COMMAND(ID_HELP, CMDIFrameWnd::OnHelp)
   ON_COMMAND(ID_CONTEXT_HELP, CMDIFrameWnd::OnContextHelp)
   ON_COMMAND(ID_DEFAULT_HELP, CMDIFrameWnd::OnHelpFinder)
END_MESSAGE_MAP()

For an SDI application, references to CMDIFrameWnd in this code are replaced by references to CFrameWnd.

About the Help Commands

The four help-related message-map entries follow the // Global help commands comment. The following table explains the purpose of each command ID used in these entries.

Help-Related Command IDs

Command ID | Purpose
ID_HELP_FINDER | Responds to the Help Topics item on the Help menu by displaying the Windows Contents screen.
ID_HELP | Responds to F1 by displaying a specific topic in Windows Help.
ID_CONTEXT_HELP | Responds to SHIFT+F1 by putting the application into Help mode.
ID_DEFAULT_HELP | Used when a specific help context cannot be found.

Notice that all of these commands are mapped to member functions of class CMDIFrameWnd (in the case of an MDI application), or to CFrameWnd (in the case of an SDI application). Unlike most of the other commands you place into the message map, these have handler functions that are predefined by the class library. Making the message-map entry enables the command.

The application’s accelerator table defines F1 for ID_HELP and SHIFT+F1 for ID_CONTEXT_HELP. You can change the keys used for these help functions by using Visual C++ to change the key values in the accelerator table.

When the user chooses a Help menu command (or uses one of the context-sensitive Help techniques described in F1 Help Support and SHIFT+F1 Help Support in the article Help: F1 and SHIFT+F1 Help), the framework calls the CWinApp::WinHelp member function. This action, in turn, starts the Windows Help program and passes context information to it.

Completing Your Application’s Help

Once you have used AppWizard to provide the generic help support, you can complete the help for your application by doing the following:

  1. Add application-specific user-interface elements.

    Use the integrated development environment to create your application’s dialog boxes, menus, and other resources.

  2. Write application-specific Help topics.

    Starting with the .RTF files supplied by AppWizard in your project’s HLP subdirectory, remove topics that don’t apply to your application, edit the remaining material, and add new topics for the menu commands, dialog boxes, toolbar buttons, and so on, that you added to your program. Each Help topic requires a help context ID. The help context is the same as the resource ID with an “H” added to the beginning. For example, if your application’s RESOURCE.H file contains the resource ID ID_PEN_WIDTHS, write a topic with the help-context ID HID_PEN_WIDTHS.

    This mapping between the resource ID and the help-context ID is established by the MakeHm tool. Note that the .RTF file refers the context ID as a string, while the application and the framework refer to the context ID as a number. The article Help: Authoring Help Topics describes the process of mapping these IDs to Help topics and writing the topics in your .RTF files.

  3. Compile Help. See Help: Compiling and Testing Your Help File.

See Also Example Help Contexts


Help: The Help Project File

Home | Overview | How Do I | Sample | Tutorial

This article describes the Help Project (.HPJ) file that AppWizard creates for you.

The Help Project file provides information used by the Windows Help Compiler. You can view the .HPJ file using the Microsoft Help Workshop (HCW.EXE); you can also use a text editor. Following is the .HPJ file for the Scribble sample application. When you create your project with AppWizard and choose the Context-Sensitive Help option, your application’s .HPJ file will look similar:

[OPTIONS]

CONTENTS=new_index

TITLE=Scribble Application Help

COMPRESS=true

WARNING=2

REPORT=Yes

BMROOT=..,.

ROOT=..,.

[FILES]
afxcore.rtf
afxprint.rtf

...

[ALIAS]
HIDR_MAINFRAME = main_index
HIDR_SCRIBBTYPE = HIDR_DOC1TYPE
HIDD_ABOUTBOX = HID_APP_ABOUT

HID_HT_SIZE = HID_SC_SIZE
HID_HT_HSCROLL = scrollbars
HID_HT_VSCROLL = scrollbars
HID_HT_MINBUTTON = HID_SC_MINIMIZE
HID_HT_MAXBUTTON = HID_SC_MAXIMIZE
AFX_HIDP_INVALID_FILENAME   = AFX_HIDP_default
AFX_HIDP_FAILED_TO_OPEN_DOC = AFX_HIDP_default

...

[MAP]
#include <C:\progra~1\devstu~1\vc\MFC\include\afxhelp.hm>
#include <hlp\scribble.hm>

This file lists options used by the Windows Help Compiler, the topic files with the .RTF extension to be used for the help build, bitmap files to be included in the build, equivalencies between context strings, mapping files, and more.

Of particular interest is the [MAP] section, which in this example points to two included files with the .HM (help mapping) extension.

Note Keep in mind when you name your .HPJ file that the name cannot contain spaces. Including a space in the file name causes help to compile incorrectly.

The article Help: The MakeHm Tool explains more about help-context mapping. For more information about Windows Help project files, see the Tools User’s Guide for Microsoft Win32.


Help: The MakeHm Tool

Home | Overview | How Do I | Sample | Tutorial

This article describes the tools you use to map help context IDs in your application to Help topics in your Help file. Topics covered include:

  • Help context IDs

  • Preferred resource ID prefixes

  • Example help contexts

  • Running the tools

In Windows Help, a help context consists of a string and an ID number. The help context string is what the help text author uses to identify Help topics. The help context ID number is what the programmer associates with each resource. The context strings and ID numbers are mapped together in the [MAP] section of the .HPJ file. When your application calls Windows Help, Windows Help uses the context ID your application passes to locate and display the Help topic denoted by that context. At run time, the framework manages supplying the appropriate help context ID.

To facilitate relating the windows, dialog boxes, and commands in your application to Windows Help contexts, MFC provides the MakeHm.exe tool, which creates the information used in the [MAP] section of the .HPJ file.

AppWizard’s custom build rules on the RESOURCE.H file call MakeHm.exe and then calls the Windows Help Compiler. Makehelp.bat performed this function in prior versions of Visual C++.

Help Context IDs

When you use Visual C++ to create dialog-template resources, menu commands, and the like, Visual C++ writes #define statements in a file named RESOURCE.H. For example, there might be #define statements for such symbols as IDD_MY_DIALOG and ID_PEN_WIDTHS.

The following illustrates the resource IDs that Visual C++ creates in your RESOURCE.H file and the help context IDs that the MakeHm tool creates. IDs in RESOURCE.H like

#define IDD_MY_DIALOG   2000
#define ID_MY_COMMAND    150

would be translated by MakeHm into

HIDD_MY_DIALOG    0x207d0
HID_MY_COMMAND    0x10096

Dialog-box IDs are translated to values beginning at 0x20000. Command and resource IDs are translated to values beginning at 0x10000. That is, the framework reserves specific ranges of values for different kinds of objects. For details, see the custom build rule on the RESOURCE.H file and Technical Note 28.

This format is compatible with the Help Compiler, which maps context IDs (the numbers on the right side) to context strings (the symbols on the left). Use these context strings in the .RTF Help files to identify topics.

For more information about how Visual C++ adds symbols to RESOURCE.H and how you can view and manipulate them with the Visual C++ Symbol Browser, see Browsing Through Symbols.

Preferred Resource ID Prefixes

To facilitate using MakeHm, observe the conventions in specifying IDs for your resource objects, as shown in the following table. It is important that different kinds of resource objects have different ID prefixes.

Preferred Resource ID Naming Conventions

Predefined ID | Object
IDP_ | Message-box prompt
IDD_ | Dialog-box ID
ID_ | Toolbar or menu command (IDM_ is okay too)
IDR_ | Frame-related resources
IDW_ | Control bar

For example, here’s a call to the MakeHm tool from a custom build rule:

makehm ID_,HID_,0x10000 IDM_,HIDM_,0x10000 resource.h >>"hlp\$(TargetName).hm"

Build rules expect dialog resources to be named with IDD_ prefixes. The corresponding help contexts will be named with HIDD_ prefixes.

Use the IDS_ prefix for normal string resources, and do not write Help topics for them. For string resources used in message boxes, use the IDP_ prefix and write Help topics for them so the user can get context-sensitive Help by pressing F1 while the message box is displayed.

Example Help Contexts

As your application grows, you’ll define a number of new IDs (symbols). For example, the following lists the RESOURCE.H file for the Scribble application after Step 6 of the tutorial:

//{{NO_DEPENDENCIES}}
// Visual C++ generated include file.
// Used by SCRIBBLE.RC
//
#define IDD_ABOUTBOX                   100
#define IDR_MAINFRAME                  128
#define IDR_SCRIBBTYPE                 129
#define IDD_PEN_WIDTHS                 131
#define IDC_THIN_PEN_WIDTH             1000
#define IDC_THICK_PEN_WIDTH            1001
#define IDC_DEFAULT_PEN_WIDTHS         1002
#define ID_PEN_THICK_OR_THIN           32771
#define ID_PEN_WIDTHS                  32772

Symbols defined for the Scribble tutorial include IDR_SCRIBBTYPE (Scribble’s menus and other application-specific resources), IDD_PEN_WIDTHS (a Pen Widths dialog box), ID_PEN_THICK_OR_THIN (a Thick Line command), and so on. Notice that one Scribble command, ID_EDIT_CLEAR_ALL, doesn’t appear in RESOURCE.H because it’s predefined ID in the class library. AppWizard will already have generated a Help topic for it in the .RTF files it created to get you started.

MakeHm maps these symbols to Windows Help contexts. The following excerpt from custom build rule shows a call to MakeHm:

makehm ID_,HID_,0x10000 IDM_,HIDM_,0x10000 resource.h >>"hlp\$(TargetName).hm"

After you run a custom build rule, an .HM file may look like the following:

// Commands (ID_* and IDM_*)
HID_PEN_THICK_OR_THIN         0x18003
HID_PEN_WIDTHS                0x18004

// Prompts (IDP_*)

// Resources (IDR_*)
HIDR_MAINFRAME                0x20080
HIDR_SCRIBBTYPE               0x20081

// Dialogs (IDD_*)
HIDD_ABOUTBOX                 0x20064
HIDD_PEN_WIDTHS               0x20083

// Frame Controls (IDW_*)

This file contains help contexts for two commands, two resources (menus and other application resources), and two dialog boxes.

Running the Tools

When the custom build rules detect a change in the RESOURCE.H file, they call the MakeHm tool to map the #define statements in RESOURCE.H to Windows Help strings in an .HM file. The MakeHm tool collects #define statements from RESOURCE.H and uses the command-line parameters passed to MakeHm to map defined symbols to help strings in a .HM file. For the example IDs in the previous paragraph, it would create help strings such as HIDD_MY_DIALOG and HID_PEN_WIDTHS. These context strings are formed by prefixing an “H” to the symbol found in RESOURCE.H. MakeHm also maps the ID’s numeric value to a corresponding number for the help context. An example is shown in Example Help Contexts.

The custom build rules will invoke the Windows Help Compiler (HCW.EXE) if the .HPJ file changes and HCW.EXE will uses the .HM files pointed to by the .HPJ file to set up the help contexts in your new Help file. Once you finish compiling your .HLP file, you can use it from your application.

See Also Help: Authoring Help Topics


Help: CPropertySheet and CPropertyPage

Home | Overview | How Do I | Sample | Tutorial

Objects of class CPropertySheet represent property sheets, also called tab dialog boxes. A property sheet consists of a CPropertySheet object and one or more CPropertyPage objects. A property sheet is displayed by the framework as a window with a set of tab indices, with which the user selects the current page, and an area for the currently selected page.

Using Help in Property Sheets

Help in CPropertySheet is supported by the F1 key and the Help button only. The Help button appears in the application framework by default. No intervention by the user is necessary. When the user adds the help information for each of the pages inside the property sheet, the help mechanism automatically displays the help for that page when the Help button is clicked.

You can deactivate the Help button capability by modifying m_psh in the property sheet object as follows:

mySheet.m_psh.dwFlags &= ~(PSH_HASHELP);

You can activate the Help button again with the following:

mySheet.m_psh.dwFlags |= PSH_HASHELP;

The m_psh variable is of type PROPSHEETPAGE. The dwFlags field of m_psh determines if the Help button of the property sheet (the parent of the property page) is enabled or disabled.

See Also CPropertyPage, CPropertySheet


Help: Authoring Help Topics

Home | Overview | How Do I | Sample | Tutorial

The framework manages navigation from application user interfaces to help contexts. Implementing further navigation within the Help file is the domain of help authoring rather than programming. The purpose of this article is to describe the general process of authoring and editing Help topic files. Topics covered include:

  • Editing the starter .RTF files

  • Help topics in the .RTF file

  • Topic examples

The following article helps you begin testing your help files:

Compiling and testing your Help file

For details about authoring and compiling Windows Help, see the Help Compiler User’s Guide.

The following figure shows the general process for creating a Help system for your application.

Preparing Help Files

For an example of preparing Help files, see Adding Context-Sensitive Help in Tutorials.

Editing the Help topics for any application is too big a task to work through in just one article; however, a few examples will help you get started. The examples in this article were edited with Microsoft Word for Windows, but you can use any application that can edit rich text format (.RTF) files. To make the following discussion concrete, the examples are drawn from the Scribble tutorial program, presented in Tutorials. If you want to see how Help is prepared for Scribble, look at Adding Context-Sensitive Help in Tutorials.

When you run AppWizard to start the Scribble tutorial, the wizard creates not only source code files, but also a set of files in rich text format (.RTF). These files contain starter Help topics for many of the user-interface elements that Scribble will have, including its menu commands. To complete a Help file for Scribble, follow the steps outlined in this group of Help articles. Then edit the .RTF files to fill in help material that AppWizard couldn’t supply.

You can easily upgrade your Help project files to a 4.0 format with the Windows 4.0 Help compiler included with Visual C++ version 4.0. This gives you access to the Windows 4.0 Help Workshop, a graphical help authoring environment with many useful features. Before you port any of your applications to other platforms, you must make sure that those platforms have a compiler that’s compatible with the 4.0 Help project file before upgrading.

The discussion in the rest of this article takes you through part of that process to illustrate the techniques and to point out some guidelines and tips. Scribble is used here merely as an example.

Editing the Starter .RTF Files

The .RTF files that AppWizard creates for an application such as Scribble contain starter Help topics for many elements of the Windows user interface. Some of them are fairly complete, while others are skeletal and must be filled out.

If you want to customize the Help topics supplied by AppWizard, you must do the following, using all of the .RTF files in your project’s HLP subdirectory (for example, \MYSCRIB\HLP):

  • Globally replace the placeholder string “<<YourApp>>” in the .RTF files with the name of the application: for example, replace “<<YourApp>>” with “Scribble”.

  • From the Help topics, remove any references to menu items absent in your application. Add any additional menu items to the .CNT file, which contains the information needed to create the Help Contents screen.

    For example, file PEN.RTF contains a topic for the Edit Links command, which Scribble doesn’t support.

  • Replace the directives in the Help topics with your own information. These directives are bracketed by << and >> symbols.

    Notice that because the class library predefines ID_EDIT_CLEAR_ALL, Scribble’s file PEN.RTF already contains a Help topic for the Clear All command added to the Edit menu in the Scribble tutorial. However, the skeletal directive for such commands, “<< Write application-specific help here. >>,” needs to be replaced with a real description.

  • Add topics for new commands and dialog boxes.

    Examine the listing of RESOURCE.H in Example Help Contexts in the article Help: The MakeHm Tool. It lists the following Help topics (as seen in Scribble):

    • Two resource-related HIDs (HIDR_ ), for menus and related resources

    • Two dialog-box HIDs (HIDD_ ), for the About and Pen Widths dialog boxes

    • Two command HIDs (HID_ ), for the Thick Line and Pen Widths commands

    In the Scribble tutorial, the Pen Widths dialog box is new, so new Help topics are needed for the dialog box and for two new commands. (The About dialog box is created by AppWizard, so it already has a topic in PEN.RTF.)

Help Topics in the .RTF File

Help topics in an .RTF file are separated by hard page breaks. Each topic has a name and a footnote symbol (#).

The footnote symbol (#) identifies a context string in the .RTF file as a jump or a popup. When the user clicks on a hot-link to a context string, a jump takes the user to another topic screen in the Help system, while a popup displays a small popup window containing extra information.

Other possible footnote symbols identify keywords for searching (K) and topic names ($). For more information, see the Tools User’s Guide in the Win32 SDK. If you’re using Word for Windows for .RTF files, you can examine the file PEN.RTF with hidden text displayed.

Topic Examples

To illustrate the process of adding topics, this topic shows the structure needed for a user to jump from the main contents screen in Help to a screen showing general information about the new Pen menu, and from there to screens that describe the Scribble tutorial application’s two Pen menu commands. These items are added to the PEN.RTF file.

The Main Contents Screen

The following figure shows the Help topic for the main contents screen as it appears in Microsoft Word for Windows (with hidden text displayed). The screen contains entries for six menus: File, Edit, View, Pen, Window, and Help. The Pen menu is Scribble-specific, so this jump has been added. The others are created by AppWizard.

The Main Contents Screen in PEN.RTF

Each of the menu names on this screen is a “hot spot” that links to another topic. By clicking this hot spot, the user can jump to another screen in the Help system. If you examine this screen in the PEN.RTF file using Word for Windows, you see that the menu names—such as Pen Menu— are formatted with double underlining. (This might be represented differently by another RTF editor.) Each menu name is followed immediately by a context name formatted as hidden text. For the Pen menu, this text reads “menu_pen.”

The Pen Menu Screen

The following figure shows the text in PEN.RTF for a Help screen about the Pen Menu topic. The upper part of the figure shows the text of the file; the lower part shows footnote text. All formatting and hidden text are displayed.

The Pen Menu Topic in the PEN.RTF File

The topic screen begins with a hard page break. The next line shows the footnote character, #, followed by the title to be displayed on the user’s screen, “Pen menu commands.” The rest of the screen contains descriptive text and two more hot spots for jumping to screens about the individual menu items.

The footnote text associated with the # footnote for the Pen menu is “menu_pen,” which is the help context. Jumps to this screen of the Help system must specify this help context.

Setting up this screen requires entering the hard page break and the footnote, then writing the text. In Word for Windows, for example, you use the Break command on the Insert menu to enter a hard page break. Then you use the Footnote entry on the Insert menu to specify a footnote with the special footnote character #.

Next, type the footnote text in the footnote window. Finally, type the descriptive text and format the hot-links.

A hot-link consist of the two parts:

  • Visible text, such as “Pen Widths,” formatted as double underlined, to designate how the hot-link looks onscreen.

  • Hidden text, such as “pen_widths,” to designate the help context of the destination topic.

In the RTF files that AppWizard supplies, tables (as in Word for Windows) are used to present groups of jumps, but help authors are not required to use tables.

A Screen for a Menu Item

The following figure shows a screen for the Pen Widths and Thick Line menu items.

The Pen Widths and Thick Line Topics in the PEN.RTF File

The screen is set up similarly to its parent screen for the Pen menu as a whole. Notice the text used for the footnotes in the lower part of the figure.


Help: Compiling and Testing Your Help File

Once your Help authoring is finished, you can compile your Help file. If you’re trying out the techniques described in these articles, perhaps by working through the Scribble tutorial in Tutorials, and you’ve chosen to author the application’s Help files, use the following procedure to see the results.

To compile and test the application’s .HLP file, use one of the following :

  • Compile the Help project (.HPJ) file from within the integrated development environment by selecting the .HPJ file from the file list and then selecting Build .hpj option from the Build menu.

  • Build your project. This will invoke the custom build rules on your project’s .hpj, .cnt and resource.h files.

  • Compile at the command line by exporting a makefile (Export makefile option in Project menu) and then issuing

    nmake /f proj.mak CFG=”proj - Win32 Debug” .\Debug\proj.hlp

  • Run HCW.EXE, load your project’s .hpj file and compile the .HLP file.

  • For Visual C++ 6.0, MakeHelp.bat is still provided by the AppWizard for projects created with support for context-sensitive help. So, you can still run MakeHelp.bat from the command line. to generate a .HLP file.

    You may have to also run VCVars32.bat by typing at the command line VCVars32 target, where target is either x86, m68k, mppc.

See Also Help: The Help Project File, Help: The MakeHm Tool


Help: More Precise Context-Sensitivity

Home | Overview | How Do I | Sample | Tutorial

F1 help and SHIFT+F1 help are activated based on help context IDs. The standard help implementation in the framework can obtain a help context from a window, dialog box, message box, menu item, or toolbar button. If you need more precise control over this mechanism, you can override parts of the mechanism.

For additional information, see Technical Note 28.


Help Topics (HTML Help): Context-Sensitive Help for Your Programs

Home

Visual C++ 6.0 ships with an online help system called HTML Help. HTML Help uses the underlying components of Microsoft Internet Explorer to display help content. HTML Help supports HTML, ActiveX, Java, scripting (JavaScript and Microsoft Visual Basic Script), and HTML image formats (.jpeg, .gif, .png).

To create online help for your application, you use the authoring tool in HTML Help called HTML Help Workshop (HHW). For more information, see "The HTML Help Components" in the online help (from within HTML Help Workshop, click the Help menu, then click Help Topics).

The topics in this section explain how to create context-sensitive help for an application by using HTML Help Workshop. Applications that use context-sensitive help typically have some kind of user interface. Commonly, an MFC (.exe), MFC ActiveX control or an ATL ActiveX control are types of applications that use context-sensitive help. The examples used in the topics in this section use handlers available in an MFC (.exe) application to implement context-sensitive help.

It is possible to use HTML Help and WinHelp in the same application.

Note In order for users of your application to access HTML Help, their computers must have the underlying components of Microsoft Internet Explorer 3.x (or later). Note that Visual Studio requires Internet Explorer 4.x.

What do you want to know more about?

Installing HTML Help

Including HTML Help Support Files in an Application

Displaying the Help Viewer

Displaying Context-Sensitive Help

Receiving HTML Help Notification Messages in an MFC Application

Automatically Building Your .chm File

See Also

Help Topics (WinHelp): Context-Sensitive Help for Your Programs


Installing HTML Help

Home

Check your computer to see if HTML Help is already installed. It will be one of the programs on the Start menu. If your computer does not have HTML Help installed, you can install it in one of two ways.

To install HTML Help

  • Run Htmlhelp.exe, which is located in the \HtmlHelp subdirectory on Disc 1 of your Visual C++ or Visual Studio CDs. In a typical installation, HTML Help is installed in \Program Files\HTML Help Workshop.

  • Download the latest sources for HTML Help from http://www.microsoft.com/workshop/author/htmlhelp.

To get more information on HTML Help

  1. Run HTML Help Workshop. After installation, HTML Help will be available from the Start menu in Programs.

  2. From the Help menu, click Help Topics.

For more information on context-sensitive help, regardless of whether you implement it using WinHelp or HTML Help, see Help Topics (WinHelp): Context-Sensitive Help for Your Programs.

Back to Help Topics (HTML Help)


Including HTML Help Support Files in an Application

Home

This topic discusses how to include the required HTML Help files in your application.

To include the required HTML Help files in your application:

  1. Include Htmlhelp.lib in your project:
    1. In Visual C++, on the Project menu, click Settings... .

    2. In the Project Settings dialog box, click the Link tab, then select the Input category.

    3. Under the Additional library path, specify the directory location of the Htmlhelp.lib file on your computer.
  2. Include Htmlhelp.h in your project:
    1. On the Project menu, click Settings... .

    2. In the Project Settings dialog box, click the C/C++ tab, then select the Preprocessor category.

    3. Under Additional include directories, specify the directory location of the Htmlhelp.h file on your computer.
  3. In the Project Settings dialog box (Project menu), specify Htmlhelp.lib as the Object/libraries module in the Link tab, General category.

  4. In your project's Stdafx.h file, insert the following line:
    #include <htmlhelp.h>

Note When using AppWizard to create an MFC (.exe) project, you do not need to select Context-sensitive help check box in Step 4, unless you also plan to use WinHelp in the application.

Back to Help Topics (HTML Help)


Displaying the Help Viewer

Home

To make the help viewer appear when the user clicks a command button or menu selection in your application:

  1. Follow the instructions in Including HTML Help Support Files in an Application.

  2. In ClassWizard, add a handler for the BN_CLICKED message (for a button) or a handler for the COMMAND message (for a menu option) to the class that contains the menu option or button. The handler should implement a call into your .chm (compiled HTML Help file). For example:
    HtmlHelp(NULL, "My_chm.chm::/A_topic.htm", HH_DISPLAY_TOPIC, 0);

For more information, use the online help in HTML Help Workshop and see the following topics:

  • About context-sensitive help

  • HtmlHelp API Reference

Back to Help Topics (HTML Help)


Displaying Context-Sensitive Help

Home

Context-sensitive help, for the purpose of this discussion, refers to help support for the controls in a dialog box that users access with:

  • The F1 key.

  • By right-clicking a control (What's This? Help).

  • By using the question-mark pointer (the What's This? Help pointer).

Context-sensitive help also refers to accessing the help viewer via a command button or menu option.

To implement help for a dialog-box control, you must first create a text file that you include in your HTML Help project and then create a two-dimensional array. Then, you can implement code that supports F1, right-click, or question-mark-pointer access to text in the help file.

The source information for context-sensitive help is stored in a .txt file that you include in your HTML Help project.

To create the context-sensitive help text file

  1. Use a text editor to create a .txt file.

  2. Format the topics as follows:
    .topic 1
help text for control 1
.topic 2
help text for control 2

Note   For more information, see "Designing context-sensitive help" in HTML Help's online help. From the Help menu (in HTML Help Workshop), choose Help Topics.

To support help for resources in a dialog box, you must create a two-dimensional array that maps control IDs to help IDs (topic numbers).

To create the two-dimensional array

  • In the .cpp file, for every class that represents a dialog box, add a two-dimensional array to the end of the class. For example:

    static DWORD myarray[] = {
IDC_CHECK1, 1,
IDC_CHECK2, 2,
IDC_CHECK3, -1,
0,0
};

    •

Each entry in the two-dimensional array pairs a resource ID for a dialog-box control with a topic number from the context-sensitive help text file. If you do not want a specific resource to have What's This? Help, use –1. The last pair in this array should be 0,0.

What's This? Help displays the control's help when a user right-clicks the control.

To implement right-click What's This? Help

  • Implement a handler for the WM_CONTEXTMENU message (in each dialog-box class where you want What's This? Help) and implement the following code for the handler:

    void CMyDialog::OnContextMenu(CWnd* pWnd, CPoint point)
{
HtmlHelp(
pWnd->GetSafeHwnd(),
"my_chm.chm::/ctrlhlp.txt",
HH_TP_HELP_CONTEXTMENU,
(DWORD)(LPVOID)myarray);
}

    •

F1 access to context-sensitive help means that users will be able to press F1 when a control has focus to access help.

To implement F1 access to context-sensitive help

  • Implement a handler for the WM_HELPINFO message (in each dialog-box class where you want F1 access to context-sensitive help) and implement the following code for the handler:

    BOOL CMyDialog::OnHelpInfo(HELPINFO* pHelpInfo)
{
if (pHelpInfo->iContextType == HELPINFO_WINDOW)
{
return HtmlHelp(
(HWND)pHelpInfo->hItemHandle,
"my_chm.chm::/ctrlhlp.txt",
HH_TP_HELP_WM_HELP,
(DWORD)(LPVOID)myarray)
!= NULL;
}
return TRUE;
}

    •

If you already implement F1 access to context-sensitive help, you can easily enable the What's This? pointer, which causes a question mark to appear on the title bar, in the upper right-hand corner of the dialog box.

To enable the What's This? Help question-mark pointer

  • Select the Context help check box in the Extended Styles tab of the dialog box properties.
    •

Back to Help Topics (HTML Help)


Receiving HTML Help Notification Messages in an MFC Application

Home

To receive notification messages from HTML Help within an MFC program, you must:

  1. Define a symbol in your Visual C++ project. This example uses a symbol called ID_HHNOTIFICATION.
    • To define a symbol, right click the high-level folder in ResourceView and select Resource Symbols.

    • In the Resource Symbols dialog box, click New and define the new symbol.
  2. In your Visual C++ project, initialize the HH_WINTYPE structure and call the HTMLHelp function to set this structure using the HH_SET_WIN_TYPE command. Use ID_HHNOTIFICATION for the idNotify field in the structure.

  3. Define the handler for your custom notification message.
    • Place a function prototype for the handler, called OnNavComplete, in your class' .h file. For example:
      protected:
//{{AFX_MSG(CMainFrame)
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
//}}AFX_MSG
void OnNavComplete(NMHDR*, LRESULT*);
DECLARE_MESSAGE_MAP()
    • Place an entry in your class's message map as follows:
      BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
//{{AFX_MSG_MAP(CMainFrame)
ON_WM_CREATE()
ON_NOTIFY(HHN_NAVCOMPLETE, ID_HHNOTIFICATION, OnNavComplete)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
    • Define a function, OnNavComplete, to handle the notifications.

Back to Help Topics (HTML Help)


Automatically Building Your .chm File

Home

Custom build rules in Visual C++ can build a .chm file anytime any of the sources to the .chm file change.

To add a custom build rule to build the latest version of the .chm

  1. Add the HTML Help Project file (.hhp) to a Visual C++ project. From the Project menu, click Add To Project, then choose Files options to access the Insert Files into Project dialog box.

  2. Select Settings… from the Project menu to access the Project Settings dialog box.

  3. Select the .hhp file in the Settings For: list and click the Custom Build tab.

  4. The Commands entry for the build rule should resemble:
    hhc.exe $(InputName).hhp
@echo off

    You may need to specify absolute or relative paths to the hhc.exe and .hhp file. You can put hhc.exe in your project's search path:

    • Select Options… from the Tools menu.

    • Click on the Directories tab and select Executable files from the Show directories for: list.

    • Specify the directory containing the hhc.exe file in the Directories list.
  5. The Outputs entry should resemble:
    $(InputName).chm

    You may have to specify an absolute or relative path to ensure that the output file is written to the desired location.

  6. If you want to rebuild the .chm file after a .htm file changes but where the .chm file wa not rebuilt, you should click the Dependencies... button in the Project Settings dialog box and specify each .htm file, including the path if necessary, to your HTML Help project.

Back to Help Topics (HTML Help)


Menu Topics

Home | Overview | How Do I | Sample

MFC helps you with two kinds of menu manipulation:

  • Adding, deleting, and modifying menus on the fly.

  • Updating the enabled/disabled state of menu items (and toolbar buttons with the same command ID) as program conditions change.

What do you want to know more about?

  • Manipulating menu objects during program execution

  • Updating menu items as program conditions change


Manipulating Menus During Program Execution

Home | Overview | How Do I | Sample

Use class CMenu to manipulate menus and menu items on the fly. CMenu encapsulates a Windows HMENU handle and supplies member functions for working with menus.

See the overview for class CMenu for details.


How to Update User-Interface Objects

Home | Overview | How Do I | Sample

Typically, menu items and toolbar buttons have more than one state. For example, a menu item is grayed (dimmed) if it is unavailable in the present context. Menu items can also be checked or unchecked. A toolbar button can also be disabled if unavailable, or it can be checked.

Who updates the state of these items as program conditions change? Logically, if a menu item generates a command that is handled by, say, a document, it makes sense to have the document update the menu item. The document probably contains the information on which the update is based.

If a command has multiple user-interface objects (perhaps a menu item and a toolbar button), both are routed to the same handler function. This encapsulates your user-interface update code for all of the equivalent user-interface objects in a single place.

The framework provides a convenient interface for automatically updating user-interface objects. You can choose to do the updating in some other way, but the interface provided is efficient and easy to use.

The following topics explain the use of update handlers:

  • When update handlers are called

  • The ON_UPDATE_COMMAND_UI macro

  • The CCmdUI class


When Update Handlers Are Called

Home | Overview | How Do I | Sample

Suppose the user clicks the mouse in the File menu, which generates a WM_INITMENUPOPUP message. The framework’s update mechanism collectively updates all items on the File menu before the menu drops down so the user can see it.

To do this, the framework routes update commands for all menu items in the pop-up menu along the standard command routing. Command targets on the routing have an opportunity to update any menu items by matching the update command with an appropriate message-map entry (of the form ON_UPDATE_COMMAND_UI) and calling an “update handler” function. Thus, for a menu with six menu items, six update commands are sent out. If an update handler exists for the command ID of the menu item, it is called to do the updating. If not, the framework checks for the existence of a handler for that command ID and enables or disables the menu item as appropriate.

If the framework does not find an ON_UPDATE_COMMAND_UI entry during command routing, it automatically enables the user-interface object if there is an ON_COMMAND entry somewhere with the same command ID. Otherwise, it disables the user-interface object. Therefore, to ensure that a user-interface object is enabled, supply a handler for the command the object generates or supply an update handler for it. See the figure in the topic User-Interface Objects and Command IDs.

It is possible to disable the default disabling of user-interface objects. For more information, see the m_bAutoMenuEnable member of class CFrameWnd in the Class Library Reference.

Menu initialization is automatic in the framework, occurring when the application receives a WM_INITMENUPOPUP message. During the idle loop, the framework searches the command routing for button update handlers in much the same way as it does for menus.


The ON_UPDATE_COMMAND_UI Macro

Home | Overview | How Do I | Sample

Use ClassWizard to connect a user-interface object to a command-update handler in a command-target object. It will automatically connect the user-interface object’s ID to the ON_UPDATE_COMMAND_UI macro and create a handler in the object that will handle the update.

For example, the Scribble tutorial in Tutorials updates a Clear All command in its Edit menu. In the tutorial, ClassWizard adds a message-map entry in the chosen class, a function declaration for a command-update handler called OnUpdateEditClearAll in the class declaration, and an empty function template in the class’s implementation file. The function prototype looks like this:

afx_msg void OnUpdateEditClearAll( CCmdUI* pCmdUI );

Like all handlers, the function shows the afx_msg keyword. Like all update handlers, it takes one argument, a pointer to a CCmdUI object.


The CCmdUI Class

Home | Overview | How Do I | Tutorial

When it routes an update command to its handler, the framework passes the handler a pointer to a CCmdUI object (or to an object of a CCmdUI-derived class). This object represents the menu item or toolbar button or other user-interface object that generated the command. The update handler calls member functions of the CCmdUI structure through the pointer to update the user-interface object. For example, here is an update handler for the Clear All menu item:

void CMyClass::OnUpdateToolsMyTool( CCmdUI* pCmdUI )
{
    if( ToolAvailable() )
        pCmdUI->Enable( TRUE );
}

This handler calls the Enable member function of an object with access to the menu item. Enable makes the item available for use.


Printing and Print Preview Topics

Home | Overview | How Do I | Sample | Tutorial

This family of articles explains how printing is implemented in the Microsoft Foundation Class Library (MFC) and how to take advantage of the printing architecture already built into the framework. The articles also explain how MFC supports easy implementation of print preview functionality and how you can use and modify that functionality.

What do you want to know more about?

  • Printing

  • My role in printing vs. the MFC framework’s role

  • Printing multipage documents

  • The printing loop

  • Pagination

  • Printer pages vs. document pages

  • Printing headers and footers

  • Allocating GDI resources for printing

  • Print preview

  • Modifying print preview


Printing

Home | Overview | How Do I | Sample | Tutorial

Microsoft Windows implements device-independent display. In MFC, this means that the same drawing calls, in the OnDraw member function of your view class, are responsible for drawing on the display and on other devices, such as printers. For print preview, the target device is a simulated printer output to the display.

Your Role in Printing vs. the Framework’s Role

Your view class has the following responsibilities:

  • Inform the framework how many pages are in the document.

  • When asked to print a specified page, draw that portion of the document.

  • Allocate and deallocate any fonts or other graphics device interface (GDI) resources needed for printing.

  • If necessary, send any escape codes needed to change the printer mode before printing a given page, for example, to change the printing orientation on a per-page basis.

The framework’s responsibilities are as follows:

  • Display the Print dialog box.

  • Create a CDC object for the printer.

  • Call the StartDoc and EndDoc member functions of the CDC object.

  • Repeatedly call the StartPage member function of the CDC object, inform the view class which page should be printed, and call the EndPage member function of the CDC object.

  • Call overridable functions in the view at the appropriate times.

The following articles discuss how the framework supports printing and print preview:

What do you want to know more about?

  • How default printing is done

  • Multipage documents

  • Headers and footers

  • Allocating GDI resources for printing

  • Print preview

  • Enhancing your printed documents (a tutorial)


Printing: How Default Printing Is Done

Home | Overview | How Do I | Sample | Tutorial

This article explains the default printing process in Windows in terms of the MFC framework.

In MFC applications, the view class has a member function named OnDraw that contains all the drawing code. OnDraw takes a pointer to a CDC object as a parameter. That CDC object represents the device context to receive the image produced by OnDraw. When the window displaying the document receives a WM_PAINT message, the framework calls OnDraw and passes it a device context for the screen (a CPaintDC object, to be specific). Accordingly, OnDraw’s output goes to the screen.

In programming for Windows, sending output to the printer is very similar to sending output to the screen. This is because the Windows graphics device interface (GDI) is hardware-independent. You can use the same GDI functions for screen display or for printing simply by using the appropriate device context. If the CDC object that OnDraw receives represents the printer, OnDraw’s output goes to the printer.

This explains how MFC applications can perform simple printing without requiring extra effort on your part. The framework takes care of displaying the Print dialog box and creating a device context for the printer. When the user selects the Print command from the File menu, the view passes this device context to OnDraw, which draws the document on the printer.

However, there are some significant differences between printing and screen display. When you print, you have to divide the document into distinct pages and display them one at a time, rather than display whatever portion is visible in a window. As a corollary, you have to be aware of the size of the paper (whether it’s letter size, legal size, or an envelope). You may want to print in different orientations, such as landscape or portrait mode. The Microsoft Foundation Class Library can’t predict how your application will handle these issues, so it provides a protocol for you to add these capabilities.

That protocol is described in the article Printing: Multipage Documents.


Printing: Multipage Documents

Home | Overview | How Do I | Sample | Tutorial

This article describes the Windows printing protocol and explains how to print documents that contain more than one page. The article covers the following topics:

  • Printing protocol

  • Overriding view class functions

  • Pagination

  • Printer pages vs. document pages

  • Print-time pagination

The Printing Protocol

To print a multipage document, the framework and view interact in the following manner. First the framework displays the Print dialog box, creates a device context for the printer, and calls the StartDoc member function of the CDC object. Then, for each page of the document, the framework calls the StartPage member function of the CDC object, instructs the view object to print the page, and calls the EndPage member function. If the printer mode must be changed before starting a particular page, the view object sends the appropriate escape code by calling the Escape member function of the CDC object. When the entire document has been printed, the framework calls the EndDoc member function.

Overriding View Class Functions

The CView class defines several member functions that are called by the framework during printing. By overriding these functions in your view class, you provide the connections between the framework’s printing logic and your view class’s printing logic. The following table lists these member functions.

CView’s Overridable Functions for Printing

Name | Reason for overriding
OnPreparePrinting | To insert values in the Print dialog box, especially the length of the document
OnBeginPrinting | To allocate fonts or other GDI resources
OnPrepareDC | To adjust attributes of the device context for a given page, or to do print-time pagination
OnPrint | To print a given page
OnEndPrinting | To deallocate GDI resources

You can do printing-related processing in other functions as well, but these functions are the ones that drive the printing process.

The following figure illustrates the steps involved in the printing process and shows where each of CView’s printing member functions are called. The rest of this article explains most of these steps in more detail. Additional parts of the printing process are described in the article Printing: Allocating GDI Resources.

The Printing Loop

Pagination

The framework stores much of the information about a print job in a CPrintInfo structure. Several of the values in CPrintInfo pertain to pagination; these values are accessible as shown in the following table.

Page Number Information Stored in CPrintInfo

Member variable or function name(s) | Page number referenced
GetMinPage/SetMinPage | First page of document
GetMaxPage/SetMaxPage | Last page of document
GetFromPage | First page to be printed
GetToPage | Last page to be printed
m_nCurPage | Page currently being printed

Page numbers start at 1, that is, the first page is numbered 1, not 0. For more information about these and other members of CPrintInfo, see the Class Library Reference.

At the beginning of the printing process, the framework calls the view’s OnPreparePrinting member function, passing a pointer to a CPrintInfo structure. AppWizard provides an implementation of OnPreparePrinting that calls DoPreparePrinting, another member function of CView. DoPreparePrinting is the function that displays the Print dialog box and creates a printer device context.

At this point the application doesn’t know how many pages are in the document. It uses the default values 1 and 0xFFFF for the numbers of the first and last page of the document. If you know how many pages your document has, override OnPreparePrinting and call SetMaxPage for the CPrintInfo structure before you send it to DoPreparePrinting. This lets you specify the length of your document.

DoPreparePrinting then displays the Print dialog box. When it returns, the CPrintInfo structure contains the values specified by the user. If the user wishes to print only a selected range of pages, he or she can specify the starting and ending page numbers in the Print dialog box. The framework retrieves these values using the GetFromPage and GetToPage functions of CPrintInfo. If the user doesn’t specify a page range, the framework calls GetMinPage and GetMaxPage and uses the values returned to print the entire document.

For each page of a document to be printed, the framework calls two member functions in your view class, OnPrepareDC and OnPrint, and passes each function two parameters: a pointer to a CDC object and a pointer to a CPrintInfo structure. Each time the framework calls OnPrepareDC and OnPrint, it passes a different value in the m_nCurPage member of the CPrintInfo structure. In this way the framework tells the view which page should be printed.

The OnPrepareDC member function is also used for screen display. It makes adjustments to the device context before drawing takes place. OnPrepareDC serves a similar role in printing, but there are a couple of differences: first, the CDC object represents a printer device context instead of a screen device context, and second, a CPrintInfo object is passed as a second parameter. (This parameter is NULL when OnPrepareDC is called for screen display.) Override OnPrepareDC to make adjustments to the device context based on which page is being printed. For example, you can move the viewport origin and the clipping region to ensure that the appropriate portion of the document gets printed.

The OnPrint member function performs the actual printing of the page. The article Printing: How Default Printing Is Done shows how the framework calls OnDraw with a printer device context to perform printing. More precisely, the framework calls OnPrint with a CPrintInfo structure and a device context, and OnPrint passes the device context to OnDraw. Override OnPrint to perform any rendering that should be done only during printing and not for screen display. For example, to print headers or footers (see the article Printing: Headers and Footers for more information). Then call OnDraw from the override of OnDraw to do the rendering common to both screen display and printing.

The fact that OnDraw does the rendering for both screen display and printing means that your application is WYSIWYG: “What you see is what you get.” However, suppose you aren’t writing a WYSIWYG application. For example, consider a text editor that uses a bold font for printing but displays control codes to indicate bold text on the screen. In such a situation, you use OnDraw strictly for screen display. When you override OnPrint, substitute the call to OnDraw with a call to a separate drawing function. That function draws the document the way it appears on paper, using the attributes that you don’t display on the screen.

Printer Pages vs. Document Pages

When you refer to page numbers, it’s sometimes necessary to distinguish between the printer’s concept of a page and a document’s concept of a page. From the point of view of the printer, a page is one sheet of paper. However, one sheet of paper doesn’t necessarily equal one page of the document. For example, if you’re printing a newsletter, where the sheets are to be folded, one sheet of paper might contain both the first and last pages of the document, side by side. Similarly, if you’re printing a spreadsheet, the document doesn’t consist of pages at all. Instead, one sheet of paper might contain rows 1 through 20, columns 6 through 10.

All the page numbers in the CPrintInfo structure refer to printer pages. The framework calls OnPrepareDC and OnPrint once for each sheet of paper that will pass through the printer. When you override the OnPreparePrinting function to specify the length of the document, you must use printer pages. If there is a one-to-one correspondence (that is, one printer page equals one document page), then this is easy. If, on the other hand, document pages and printer pages do not directly correspond, you must translate between them. For example, consider printing a spreadsheet. When overriding OnPreparePrinting, you must calculate how many sheets of paper will be required to print the entire spreadsheet and then use that value when calling the SetMaxPage member function of CPrintInfo. Similarly, when overriding OnPrepareDC, you must translate m_nCurPage into the range of rows and columns that will appear on that particular sheet and then adjust the viewport origin accordingly.

Print-Time Pagination

In some situations, your view class may not know in advance how long the document is until it has actually been printed. For example, suppose your application isn’t WYSIWYG, so a document’s length on the screen doesn’t correspond to its length when printed.

This causes a problem when you override OnPreparePrinting for your view class: you can’t pass a value to the SetMaxPage function of the CPrintInfo structure, because you don’t know the length of a document. If the user doesn’t specify a page number to stop at using the Print dialog box, the framework doesn’t know when to stop the print loop. The only way to determine when to stop the print loop is to print out the document and see when it ends. Your view class must check for the end of the document while it is being printed, and then inform the framework when the end is reached.

The framework relies on your view class’s OnPrepareDC function to tell it when to stop. After each call to OnPrepareDC, the framework checks a member of the CPrintInfo structure called m_bContinuePrinting. Its default value is TRUE. As long as it remains so, the framework continues the print loop. If it is set to FALSE, the framework stops. To perform print-time pagination, override OnPrepareDC to check whether the end of the document has been reached, and set m_bContinuePrinting to FALSE when it has.

The default implementation of OnPrepareDC sets m_bContinuePrinting to FALSE if the current page is greater than 1. This means that if the length of the document wasn’t specified, the framework assumes the document is one page long. One consequence of this is that you must be careful if you call the base class version of OnPrepareDC. Do not assume that m_bContinuePrinting will be TRUE after calling the base class version.

What do you want to know more about?

  • Headers and footers

  • Allocating GDI resources

See Also CView, CDC


Printing: Headers and Footers

Home | Overview | How Do I | Sample | Tutorial

This article explains how to add headers and footers to a printed document.

When you look at a document on the screen, the name of the document and your current location in the document are commonly displayed in a title bar and a status bar. When looking at a printed copy of a document, it’s useful to have the name and page number shown in a header or footer. This is a common way in which even WYSIWYG programs differ in how they perform printing and screen display.

The OnPrint member function is the appropriate place to print headers or footers because it is called for each page, and because it is called only for printing, not for screen display. You can define a separate function to print a header or footer, and pass it the printer device context from OnPrint. You might need to adjust the window origin or extent before calling OnDraw to avoid having the body of the page overlap the header or footer. You might also have to modify OnDraw because the amount of the document that fits on the page could be reduced.

One way to compensate for the area taken by the header or footer is to use the m_rectDraw member of CPrintInfo. Each time a page is printed, this member is initialized with the usable area of the page. If you print a header or footer before printing the body of the page, you can reduce the size of the rectangle stored in m_rectDraw to account for the area taken by the header or footer. Then OnPrint can refer to m_rectDraw to find out how much area remains for printing the body of the page.

You cannot print a header, or anything else, from OnPrepareDC, because it is called before the StartPage member function of CDC has been called. At that point, the printer device context is considered to be at a page boundary. You can perform printing only from the OnPrint member function.

What do you want to know more about?

  • Printing multipage documents

  • Allocating GDI resources for printing


Printing: Allocating GDI Resources

Home | Overview | How Do I | Sample | Tutorial

This article explains how to allocate and deallocate the Windows graphics device interface (GDI) objects needed for printing.

Suppose you need to use certain fonts, pens, or other GDI objects for printing, but not for screen display. Because of the memory they require, it’s inefficient to allocate these objects when the application starts up. When the application isn’t printing a document, that memory might be needed for other purposes. It’s better to allocate them when printing begins, and then delete them when printing ends.

To allocate these GDI objects, override the OnBeginPrinting member function. This function is well suited to this purpose for two reasons: the framework calls this function once at the beginning of each print job and, unlike OnPreparePrinting, this function has access to the CDC object representing the printer device driver. You can store these objects for use during the print job by defining member variables in your view class that point to GDI objects (for example, CFont * members, and so on).

To use the GDI objects you’ve created, select them into the printer device context in the OnPrint member function. If you need different GDI objects for different pages of the document, you can examine the m_nCurPage member of the CPrintInfo structure and select the GDI object accordingly. If you need a GDI object for several consecutive pages, Windows requires that you select it into the device context each time OnPrint is called.

To deallocate these GDI objects, override the OnEndPrinting member function. The framework calls this function at the end of each print job, giving you the opportunity to deallocate printing-specific GDI objects before the application returns to other tasks.

See Also Printing: How Default Printing Is Done


Printing: The Print Preview Architecture

Home | Overview | How Do I | Sample | Tutorial

This article explains how the MFC framework implements print preview functionality. Topics covered include:

  • Print preview process

  • Modifying print preview

Print preview is somewhat different from screen display and printing because, instead of directly drawing an image on a device, the application must simulate the printer using the screen. To accommodate this, the Microsoft Foundation Class Library defines a special (undocumented) class derived from CDC, called CPreviewDC. All CDC objects contain two device contexts, but usually they are identical. In a CPreviewDC object, they are different: the first represents the printer being simulated, and the second represents the screen on which output is actually displayed.

The Print Preview Process

When the user selects the Print Preview command from the File menu, the framework creates a CPreviewDC object. Whenever your application performs an operation that sets a characteristic of the printer device context, the framework also performs a similar operation on the screen device context. For example, if your application selects a font for printing, the framework selects a font for screen display that simulates the printer font. Whenever your application would send output to the printer, the framework instead sends the output to the screen.

Print preview also differs from printing in the order that each draws the pages of a document. During printing, the framework continues a print loop until a certain range of pages has been rendered. During print preview, one or two pages are displayed at any time, and then the application waits; no further pages are displayed until the user responds. During print preview, the application must also respond to WM_PAINT messages, just as it does during ordinary screen display.

The OnPreparePrinting function is called when preview mode is invoked, just as it is at the beginning of a print job. The CPrintInfo structure passed to the function contains several members whose values you can set to adjust certain characteristics of the print preview operation. For example, you can set the m_nNumPreviewPages member to specify whether you want to preview the document in one-page or two-page mode.

Modifying Print Preview

You can modify the behavior and appearance of print preview in a number of ways rather easily. For example, you can, among other things:

  • Cause the print preview window to display a scroll bar for easy access to any page of the document.

  • Cause print preview to maintain the user’s position in the document by beginning its display at the current page.

  • Cause different initialization to be performed for print preview and printing.

  • Cause print preview to display page numbers in your own formats.

If you know how long the document is and call SetMaxPage with the appropriate value, the framework can use this information in preview mode as well as during printing. Once the framework knows the length of the document, it can provide the preview window with a scroll bar, allowing the user to page back and forth through the document in preview mode. If you haven’t set the length of the document, the framework cannot position the scroll box to indicate the current position, so the framework doesn’t add a scroll bar. In this case, the user must use the Next Page and Previous Page buttons on the preview window’s control bar to page through the document.

For print preview, you may find it useful to assign a value to the m_nCurPage member of CPrintInfo, even though you would never do so for ordinary printing. During ordinary printing, this member carries information from the framework to your view class. This is how the framework tells the view which page should be printed.

By contrast, when print preview mode is started, the m_nCurPage member carries information in the opposite direction: from the view to the framework. The framework uses the value of this member to determine which page should be previewed first. The default value of this member is 1, so the first page of the document is displayed initially. You can override OnPreparePrinting to set this member to the number of the page being viewed at the time the Print Preview command was invoked. This way, the application maintains the user’s current position when moving from normal display mode to print preview mode.

Sometimes you may want OnPreparePrinting to perform different initialization depending on whether it is called for a print job or for print preview. You can determine this by examining the m_bPreview member variable in the CPrintInfo structure. This member is set to TRUE when print preview is invoked.

The CPrintInfo structure also contains a member named m_strPageDesc, which is used to format the strings displayed at the bottom of the screen in single-page and multiple-page modes. By default these strings are of the form “Page n” and “Pages n - m,” but you can modify m_strPageDesc from within OnPreparePrinting and set the strings to something more elaborate. See CPrintInfo in the Class Library Reference for more information.

See Also Printing, CView, CDC


Property Sheet Topics

Home | Overview | How Do I | Sample

A property sheet, also known as a tab dialog box, provides a way to manage large numbers of controls in a dialog box. The property sheet contains property pages, each based on a separate dialog template resource. You can divide your dialog box’s controls into logical groups and put each group on its own property page.

What do you want to know more about?

  • What property sheets are

  • What property pages are

  • How to create a property sheet dialog box

  • Styles for property page dialog templates

  • Class CPropertySheet

  • Class CPropertyPage

  • How to add a property page to a property sheet

  • How to display a property sheet

  • How to add controls to a property sheet (as opposed to a property page)

  • Exchanging data between a property sheet and your program

  • How to create a modeless property sheet

  • How to handle the Apply button


Property Sheets

Home | Overview | How Do I | Sample

The Microsoft Foundation Class Library (MFC) contains support for property sheets, also known as tab dialog boxes, in classes CPropertySheet and CPropertyPage. This family of articles explains how and when to use property sheets in your MFC applications. Topics include:

  • Using property sheets in your application

  • Adding controls to a property sheet

A property sheet is a special kind of dialog box that is generally used to modify the attributes of some external object, such as the current selection in a view. The property sheet has three main parts: the containing dialog box, one or more property pages shown one at a time, and a tab at the top of each page that the user clicks to select that page. Property sheets are useful for situations where you have a number of similar groups of settings or options to change. An example of a property sheet is the Project Settings dialog box in the integrated development environment. In this case, there are a number of different groups of options that need to be set. The property sheet allows a large amount of information to be grouped in an easily understood fashion.

Other articles in this family include:

  • Property Sheets: Exchanging Data

  • Property Sheets: Creating a Modeless Property Sheet

  • Property Sheets: Handling the Apply Button


Using Property Sheets in Your Application

Home | Overview | How Do I | Sample

To use a property sheet in your application, complete the following steps:

  1. Create a dialog template resource for each property page. Keep in mind that the user may be switching from one page to another, so lay out each page as consistently as possible.

    The dialog templates for all pages do not have to be the same size. The framework uses the size of the largest page to determine how much space to allocate in the property sheet for the property pages.

    When you create the dialog template resource for a property page, you must specify the following styles in the Dialog Properties property sheet:

    • Set the Caption edit box on the General page to the text you wish to appear in the tab for this page.

    • Set the Style list box on the Styles page to Child.

    • Set the Border list box on the Styles page to Thin.

    • Ensure that the Titlebar check box on the Styles page is selected.

    • Ensure that the Disabled check box on the More Styles page is selected.
  2. Use ClassWizard to create a CPropertyPage-derived class corresponding to each property page dialog template. To do this, choose ClassWizard from the View menu while the focus is on a particular property page dialog box. Choose CPropertyPage as the base class in ClassWizard.

  3. Using ClassWizard, create member variables to hold the values for this property page. The process for adding member variables to a property page is exactly the same as adding member variables to a dialog box, because a property page is a specialized dialog box.

  4. Construct a CPropertySheet object in your source code. Usually, you construct the CPropertySheet object in the handler for the command that displays the property sheet. This object represents the entire property sheet. If you create a modal property sheet with the DoModal function, the framework supplies three command buttons by default: OK, Cancel, and Apply. The framework creates no command buttons for modeless property sheets created with the Create function. You do not need to derive a class from CPropertySheet unless you want to either add other controls (such as a preview window) or display a modeless property sheet. This step is necessary for modeless property sheets because they do not contain any default controls that could be used to close the property sheet.

  5. For each page to be added to the property sheet, do the following:
    • Construct one object for each CPropertyPage-derived class that you created using ClassWizard earlier in this process.

    • Call CPropertySheet::AddPage for each page.

    Typically, the object that creates the CPropertySheet also creates the CPropertyPage objects in this step. However, if you implement a CPropertySheet-derived class, you can embed the CPropertyPage objects in the CPropertySheet object and call AddPage for each page from the CPropertySheet-derived class constructor. AddPage adds the CPropertyPage object to the property sheet’s list of pages but does not actually create the window for that page. Therefore, it is not necessary to wait until creation of the property sheet window to call AddPage; you can call AddPage from the property sheet’s constructor.

  6. Call CPropertySheet::DoModal or Create to display the property sheet. Call DoModal to create a property sheet as a modal dialog box. Call Create to create the property sheet as a modeless dialog box.

  7. Exchange data between property pages and the owner of the property sheet. This is explained in the article Property Sheets: Exchanging Data.

For an example of how to use property sheets, see the MFC General sample PROPDLG.


Adding Controls to a Property Sheet

Home | Overview | How Do I | Sample

By default, a property sheet allocates window area for the property pages, the tab index, and the OK, Cancel, and Apply buttons. (A modeless property sheet does not have the OK, Cancel, and Apply buttons.) You can add other controls to the property sheet. For example, you can add a preview window to the right of the property page area to show the user what the current settings would look like if applied to an external object.

You can add controls to the property sheet dialog in the OnCreate handler. Accommodating additional controls usually requires expanding the size of the property sheet dialog. After calling the base class CPropertySheet::OnCreate, call GetWindowRect to get the width and height of the currently allocated property sheet window, expand the rectangle’s dimensions, and call MoveWindow to change the size of the property sheet window.

For more information on property sheets, see the following articles:

  • Property Sheets: Exchanging Data

  • Property Sheets: Creating a Modeless Property Sheet

  • Property Sheets: Handling the Apply Button

See Also CPropertyPage, CPropertySheet


Property Sheets: Exchanging Data

Home | Overview | How Do I | Sample

As with most dialog boxes, the exchange of data between the property sheet and the application is one of the most important functions of the property sheet. This article describes how to accomplish this task.

Exchanging data with a property sheet is actually a matter of exchanging data with the individual property pages of the property sheet. The procedure for exchanging data with a property page is the same as for exchanging data with a dialog box, since a CPropertyPage object is just a specialized CDialog object. The procedure takes advantage of the framework’s dialog data exchange (DDX) facility, which exchanges data between controls in a dialog box and member variables of the dialog box object.

The important difference between exchanging data with a property sheet and with a normal dialog box is that the property sheet has multiple pages, so you must exchange data with all the pages in the property sheet. For more information on DDX, see Dialog Data Exchange and Validation.

The following example illustrates exchanging data between a view and two pages of a property sheet:

void CMyView::DoModalPropertySheet()
{
   CPropertySheet propsheet;
   CMyFirstPage pageFirst; // derived from CPropertyPage
   CMySecondPage pageSecond; // derived from CPropertyPage

   // Move member data from the view (or from the currently
   // selected object in the view, for example).
   pageFirst.m_nMember1 = m_nMember1;
   pageFirst.m_nMember2 = m_nMember2;

   pageSecond.m_strMember3 = m_strMember3;
   pageSecond.m_strMember4 = m_strMember4;

   propsheet.AddPage(&pageFirst);
   propsheet.AddPage(&pageSecond);

   if (propsheeet.DoModal() == IDOK)
   {
      m_nMember1 = pageFirst.m_nMember1;
      m_nMember2 = pageFirst.m_nMember2;
      m_strMember3 = pageSecond.m_strMember3;
      m_strMember4 = pageSecond.m_strMember4;
      GetDocument()->SetModifiedFlag();
      GetDocument()->UpdateAllViews(NULL);
   }
}

See Also Property Sheets


Property Sheets: Creating a Modeless Property Sheet

Home | Overview | How Do I | Sample

Normally, the property sheets you create will be modal. When using a modal property sheet, the user must close the property sheet before using any other part of the application. This article describes methods you can use to create a modeless property sheet that allows the user to keep the property sheet open while using other parts of the application.

To display a property sheet as a modeless dialog box instead of as a modal dialog box, call CPropertySheet::Create instead of DoModal. You must also implement some extra tasks to support a modeless property sheet.

One of the additional tasks is exchanging data between the property sheet and the external object it is modifying when the property sheet is open. This is generally the same task as for standard modeless dialog boxes. Part of this task is implementing a channel of communication between the modeless property sheet and the external object to which the property settings apply. This implementation is far easier if you derive a class from CPropertySheet for your modeless property sheet. This article assumes you have done so.

One method for communicating between the modeless property sheet and the external object (the current selection in a view, for example) is to define a pointer from the property sheet to the external object. Define a function (called something like SetMyExternalObject) in the CPropertySheet-derived class to change the pointer whenever the focus changes from one external object to another. The SetMyExternalObject function needs to reset the settings for each property page to reflect the newly selected external object. To accomplish this, the SetMyExternalObject function must be able to access the CPropertyPage objects belonging to the CPropertySheet class.

The most convenient way to provide access to property pages within a property sheet is to embed the CPropertyPage objects in the CPropertySheet-derived object. Embedding CPropertyPage objects in the CPropertySheet-derived object differs from the typical design for modal dialog boxes, where the owner of the property sheet creates the CPropertyPage objects and passes them to the property sheet via CPropertySheet::AddPage.

There are many user-interface alternatives for determining when the settings of the modeless property sheet should be applied to an external object. One alternative is to apply the settings of the current property page whenever the user changes any value. Another alternative is to provide an Apply button, which allows the user to accumulate changes in the property pages before committing them to the external object. For information on ways to handle the Apply button, see the article Property Sheets: Handling the Apply Button.

See Also Property Sheets, Property Sheets: Exchanging Data, Life Cycle of a Dialog Box


Property Sheets: Handling the Apply Button

Home | Overview | How Do I | Sample

Property sheets have a capability that standard dialog boxes do not: They allow the user to apply changes they have made before closing the property sheet. This is done using the Apply button. This article discusses methods you can use to implement this feature properly.

Modal dialog boxes usually apply the settings to an external object when the user clicks OK to close the dialog box. The same is true for a property sheet: When the user clicks OK, the new settings in the property sheet take effect.

However, you may want to allow the user to save settings without having to close the property sheet dialog box. This is the function of the Apply button. The Apply button applies the current settings in all of the property pages to the external object, as opposed to applying only the current settings of the currently active page.

By default, the Apply button is always disabled. You must write code to enable the Apply button at the appropriate times, and you must write code to implement the effect of Apply, as explained below.

If you do not wish to offer the Apply functionality to the user, it is not necessary to remove the Apply button. You can leave it disabled, as will be common among applications that use standard property sheet support available in future versions of Windows.

To report a page as being modified and enable the Apply button, call CPropertyPage::SetModified( TRUE ). If any of the pages report being modified, the Apply button will remain enabled, regardless of whether the currently active page has been modified.

You should call CPropertyPage::SetModified whenever the user changes any settings in the page. One way to detect when a user changes a setting in the page is to implement change notification handlers for each of the controls in the property page, such as EN_CHANGE or BN_CLICKED.

To implement the effect of the Apply button, the property sheet must tell its owner, or some other external object in the application, to apply the current settings in the property pages. At the same time, the property sheet should disable the Apply button by calling CPropertyPage::SetModified( FALSE ) for all pages that applied their modifications to the external object.

For an example of this process, see the MFC General sample PROPDLG.

See Also Property Sheets


Resource Editor Topics (Specific to Visual C++)

Home | Overview | How Do I

Visual C++ adds some functionality to the resource editors supplied by the integrated development environment. This family of articles covers those additions.

What do you want to know more about?

General Resource Editing Topics

  • Work with resource files

  • Import resource script files created by other applications

  • Add MFC support to resource script files

  • Use advanced resource file techniques

  • Change the name of the symbol header file

  • Use shared (read-only) or calculated symbols

  • Include resources from other files

  • Change resources while copying them

  • Change the language of a resource

  • Change the property condition of a resource

  • Import and export resources

  • Property pages for ActiveX controls and accelerator keys

Dialog Editor Topics

  • Use the dialog editor (general)

  • Use the dialog editor in Visual C++

  • Import a Visual Basic form

  • Warning messages encountered while importing a Visual Basic form

  • Limitations of imported Visual Basic controls

  • Limitations with properties and nested controls

  • Use custom controls in a dialog box

  • Tips for using the dialog editor effectively in Visual C++

Graphics Editor Topics

  • Use the graphics editor (general)

  • Use the graphics editor in Visual C++

  • Create or editing icons and cursors

Menu Editor Topics

  • Use the menu editor

  • Use the menu editor in Visual C++

  • Create pop-up menus

  • View the menu resource as a pop-up menu

  • Associate a menu item with an accelerator key

  • Associate a menu item with a status bar prompt

Symbol Editor Topics

  • Use the symbol editor (resource symbols browser) in Visual C++

  • Change a symbol or symbol name

  • Change a symbol’s numerical value

  • Use the Resource Symbols browser to manage symbols

  • Create new symbols

  • Change unassigned symbols

  • Open the resource editor for a given symbol

  • Change the name of the symbol header file

  • Use shared (read-only) or calculated symbols

Version Editor Topics

  • Use the version information editor (general)

  • Use the version editor in Visual C++

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Working with Resource Files

Home | Overview | How Do I

You can work with resources that were not developed in Visual C++'s development environment or are not part of your current project. For example, you can:

  • Work with nested and conditionally included resource files.

  • Update existing resources or convert them to Visual C++ format.

  • Import or export graphic resources to or from your current resource file.

  • Include shared or read-only identifiers (symbols) that can’t be modified by the development environment.

  • Include resources in your executable (.exe) file that don’t require editing (or that you don’t want to be edited) during your current project, such as resources that are shared between several projects.

  • Include resource types not supported by the development environment.

You can open the types of files shown in the following table and edit the resources they contain.

Filename | Description
.rc | 16- and 32-bit resource script files
.res | 16- and 32-bit resource files
.exe | 16- and 32-bit executable files
.dll | 16- and 32-bit dynamic link library files
.bmp, .dib, .ico, and .cur | Bitmap, icon, and cursor files

You can save your resources as shown in the following table.

Open file as | Save file as
.rc | .rc or 32-bit .res
16-bit .res | .rc or 16-bit .res
32-bit .res | .rc or 32-bit .res
16-bit .exe | 16-bit .exe, .rc, or 16-bit .res
32-bit .exe | 32-bit .exe, .rc, or 32-bit .res
16-bit .dll | 16-bit .dll, .rc, or 16-bit .res
32-bit .dll | 32-bit .dll, .rc, or 32-bit .res
.bmp or .dib | .bmp or .dib
.ico | .ico
.cur | .cur

Note Resource script files (.rc) are distinguished as being 16- or 32-bit by whether they contain 32-bit resource keywords (such as LANGUAGE, EXSTYLE, or DIALOGEX), not by their underlying file structure. You create a 32-bit .rc file only by adding 32-bit keywords to it.

The environment also works with the files shown in the following table during your resource editing session.

Filename | Description
Resource.h | Header file generated by the development environment; contains symbol definitions.
filename.aps | Binary version of the current resource script file; used for quick loading.
projectname.clw | File containing information about the current project; used by ClassWizard in Visual C++.
projectname.mak | File containing project build instructions.
projectname.vcp | Project configuration file.

What do you want to do?

  • Import a resource script file created by another application

  • Add MFC support to a resource script file

  • Use advanced resource file techniques


Importing Resource Script Files Created by Other Applications

Home | Overview | How Do I

The following procedure explains how to import resource script files created by other applications.

To update an existing resource script file for use within the development environment

  1. Make a backup copy of your existing resource script (.rc) file.

  2. Add the .rc file to your project.

  3. Open the .rc file in the development environment.

    Note The development environment uses the include path set using the Directories tab in the Options dialog box. In addition, relative include paths for an .rc file in the development environment for Visual C++ must be based on the directory where the .rc file is currently located.

  4. Save the new version of the .rc file.

Reading in and then saving .rc files created by other applications modifies the organization of those .rc files.


Adding MFC Support to Resource Script Files

Home | Overview | How Do I

Normally, when you build an MFC application for Windows from scratch using AppWizard, you start by generating a basic set of files (including a resource script file (.rc)) that contains the core features of the Microsoft Foundation classes. However, if you are editing an .rc file for an application for Windows that is not based on MFC, the following features specific to the MFC framework are not available:

  • ClassWizard

  • Menu prompt strings

  • List contents for combo-box controls

You can, however, add MFC support to existing .rc files that do not have it.

To add MFC support to .rc files

  1. Open the resource file.

  2. In ResourceView, highlight the resources folder.

  3. Right-click and select Properties on the shortcut menu.

  4. Select the Enable MFC Features check box.


Using Advanced Resource File Techniques

Home | Overview | How Do I

You can use the Resource Includes command on the View menu to modify the environment’s normal working arrangement of storing all resources in the project .rc file and all symbols in Resource.h. For more information on symbols, see Symbol Editor Topics.

In the Resource Includes dialog box, use the Symbol header file box to change the name of the header file where the symbol definitions for your resource file are stored.

Use the Read-only symbol directives box to include header files that contain symbols that should not be modified during an editing session. For example, you can use the Read-only symbol directives box to include a symbol file that has been created to be shared among several projects. You can also use this box to include MFC .h files.

Use the Compile-time directives box to include resource files that:

  • Are created and edited separately from the resources in your main resource file.

  • Contain compile-time directives, such as directives that conditionally include resources.

  • Contain resources in a custom format.

The Compile-time directives box is also used to include standard MFC resource files.

Once you’ve made changes to your resource file using the Resource Includes dialog box, you need to close the file and then reopen it for the changes to take effect.

What do you want to do?

  • Change the name of the symbol header file

  • Use shared (read-only) or calculated symbols

  • Include resources from other files


Including Resources from Other Files

Home | Overview | How Do I

Normally it is easy and convenient to work with the default arrangement of all resources in one resource script (.rc) file. However, you can add resources in other files to your current project at compile time by listing them in the Compile-time directives box in the Resource Includes dialog box.

There are several reasons to place resources in a file other than the main .rc file:

  • To include resources that have already been developed and tested and do not need further modification.

  • To include resources that are being used by several different projects, or that are part of a source code version-control system, and thus must exist in a central location where modifications will affect all projects.

  • To include resources (such as RCDATA resources) that are in a custom format. RCDATA resources may have special requirements. For example, you cannot use an expression as a value for the nameID field. See the Win32 SDK documentation for more information.

  • To include statements in your resource file that execute conditionally at compile time using compiler directives such as #ifdef and #else. For example, your project may have a group of resources that are bracketed by #ifdef _DEBUG ... #endif and are thus included only if the constant _DEBUG is defined at compile time.

  • To include statements in your resource file that modify resource-file syntax by using #define to implement simple macros.

If you have sections in your existing .rc files that meet any of these conditions, you should place the sections in one or more separate .rc files and include them in your project using the Resource Includes dialog box. The Projectname.rc2 file created in the \res subdirectory of a new project is used for this purpose.

To include resource files that will be added to your project at compile time

  1. Place the resources in a resource script file with a unique filename. (Do not use projectname.rc, since this is the filename used for the main resource script file.)

  2. From the View menu, choose Resource Includes.

  3. In the Compile-time directives box, use the #include compiler directive to include the new resource file in the main resource file in the development environment.

    The resources in files included in this way are made a part of your executable file at compile time. They are not directly available for editing or modification when you are working on your project’s main .rc file. You need to open included .rc files separately.

  4. Click OK.


Changing Resources While Copying Them

Home | Overview | How Do I

With Visual C++, in addition to copying resources exactly, you can also copy them while changing the resource’s language, its property condition, or both. When you create or copy a resource with a different language or condition, this is displayed after the symbol name in the Project window.

Language

The language identifies the language used for text in the resource.

Property Condition

The condition is a symbol that identifies a condition under which this copy of the resource is used.

Note You can also copy from a template (see Using Resource Templates).

What do you want to do?

  • Copy an existing resource exactly

  • Change a resource’s language or property condition while copying the resource.

  • Edit a resource’s language or property conditions (no copying).

  • Copy resources from one file to another

To copy an existing resource and change the language or condition

  1. Select the resource you want to copy.

  2. From the Insert menu, choose Resource Copy.

  3. In the Language list box, select the language.

    –or–

    In the Condition box, type the condition.

To modify the language or property conditions of a resource

  1. Right-click the resource you want to edit and select Properties.

  2. In the Dialog Properties window, edit the Language or Condition properties.

Tip The easiest way to copy resources from either an existing resource or an executable file to your current resource file is to have both .rc files open at the same time. Then use the drag-and-drop method to move items from one file to another, as illustrated in Copying Resources.

Notes To avoid conflicts with symbol names or values in the existing file, the development environment may change the transferred resource’s symbol value, or symbol name and value, when you copy it to the new file.

Visual C++ includes sample resource files that you can use in your own application. For more information, see COMMON.RES Sample Resources.


Importing and Exporting Resources

Home | Overview | How Do I

You can import images, icons, and cursors, either into your current resource file or into a separate resource file.

To import a separate image, icon, or cursor file into your current resource file

  1. From the right mouse pop-up menu, choose Import.

  2. Select the name of the image, icon, or cursor file you want to import.

  3. Click OK to add the file to the current resource file.

Tip You can also copy an image, icon, or cursor into your current resource file by dragging it from Windows Explorer and dropping it into the ResourceView pane.

To export an image, icon, or cursor as a separate file

  1. Select the image, icon, or cursor you want to export.

    The development environment exports the graphic selected in the ResourceView pane or the graphic in the currently active Image Editor window.

  2. From the right mouse pop-up menu, choose Export.

  3. If you do not want to accept the current filename, type a new one.

  4. Click OK to save the graphics file on the disk.


Property Pages for ActiveX Controls and Accelerator Keys

Home | Overview | How Do I

Property pages control the appearance and the behavior of resources and differ according to their purpose. Use the following information as a guideline for the property pages you will encounter for ActiveX controls and for accelerator keys.

ActiveX Controls

ActiveX controls supplied by independent vendors may come equipped with their own property pages and characteristics. ActiveX controls always have General and All pages, plus whatever the vendor has attached to a particular control.

Accelerator Keys

Accelerator keys have many legal entries in the key box on the property page. For more information, see Setting Accelerator Properties.


Dialog Editor Topics for Visual C++

Home | Overview | How Do I

Use the dialog editor to edit the dialog template resource that Windows uses to display a dialog box — or a form view, record view, or dialog bar.

Visual C++ allows you to import Visual Basic forms, converting them to form views or dialog boxes. There are also a few tips for using the dialog editor specific to Visual C++.

What do you want to know more about?

  • What a Visual Basic form is

Importing Forms from Visual Basic

  • Importing a Visual Basic form into the dialog editor

  • Warning messages encountered while importing a form

  • Limitations of controls imported with a form

  • Limitations with properties and nested controls

Custom Controls

  • Using custom controls in a dialog box

Dialog Editor Tips

  • Editing the properties of multiple controls in dialog editor

  • Arranging pushbuttons in dialog editor

  • Finding control labels and dialog IDs within a dialog box or across multiple dialog boxes

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Importing a Visual Basic Form

Home | Overview | How Do I

You can import a Visual Basic form in the dialog editor. A Visual Basic form resembles a dialog box and is the container within which you place controls to create the user interface for a Visual Basic application.

Some controls will also import with the form. ActiveX controls, if installed in the project, will import. Controls that are native to Visual Basic can be troublesome, and nested controls also have limitations. Most of these limitations come from differences between the Visual Basic run-time and the Windows run-time and dialog behaviors.

To import a Visual Basic form

  1. From the Insert menu, choose Resource.

  2. Click Import.

  3. Type the name of the .FRM file, or browse to locate the file.

  4. Click Import.

What do you want to know more about?

  • Warning messages when importing Visual Basic forms

  • Limitations of imported Visual Basic controls

  • Limitations with Visual Basic properties and nested controls

See Also Accelerator Editor, Binary Data Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Visual Basic Forms: Warning Messages

Home | Overview | How Do I

When importing a Visual Basic form, several warning messages may appear, with information similar to this:

  • The ActiveX control “FOOLIB.FOOCTRL” is not installed in the project.

    ActiveX controls have to be installed using the Insert ActiveX Control command. (System registry alone will not work.)

  • Syntax error in VB form description.

    The form is invalid because of customization. For example, editing or merging with a source-code file.

  • The form’s binary data file “FOO.FRX” can’t be opened.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Visual Basic Forms: Limitations of Imported Controls

Home | Overview | How Do I

The following controls are implemented in a reduced-functionality way or ignored, due to differences between the Visual Basic run-time and the Windows dialog functionality:

  • Drive and directory list boxes.

    These are converted to a Windows list box, which can be filled.

  • MDI forms.

    Imported as a normal dialog box. Menus are ignored.

  • Data controls.

  • Line and shape controls.

  • Horizontal and vertical scroll bars.

  • Timers.

  • Printers.

  • Screens.

  • Clipboards.

  • Queries.

  • Apps.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Visual Basic Forms: Limitations with Properties and Nested Controls

Home | Overview | How Do I

Several properties of Visual Basic controls are implemented only by Visual Basic and have no equivalent in Windows dialog boxes and controls. Examples include setting font and color properties for individual controls.

Nested controls, possible in Visual Basic, do not translate into the Visual C++ environment. In the Visual Basic environment, controls can be nested inside of each other. You can set the Visible state of all of the nested controls by setting the outermost control to Visible. In the Visual C++ environment, the visibility of the controls is a run-time feature.

One solution is to move the overlapping controls into separate dialog boxes. Then have the code create the dialog boxes as needed, with the main dialog box as a parent window.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Using Custom Controls in the Dialog Editor

Home | Overview | How Do I

The dialog editor lets you use existing “custom” or “user” controls in a dialog template.

Note Custom controls in this sense are not to be confused with ActiveX controls. ActiveX controls — when they were known as OLE controls — were sometimes called OLE custom controls. Also, don’t confuse these controls with the owner-drawn controls in Windows.

This functionality is intended to let you use controls other than those supplied by Windows. At run time, the control is associated with a window class (not the same as a C++ class). A more common way to accomplish the same task is to install any control, such as a static control, in your dialog box. Then at run time, in the OnInitDialog function, remove that control and replace it with your own custom control.

This is an old technique. Today you are advised in most cases to write an ActiveX control or subclass a Windows common control.

For these custom controls, you are limited to:

  • Setting the location in the dialog box.

  • Typing a caption.

  • Identifying the name of the control’s Windows class (your application code must register the control by this name).

  • Typing a 32-bit hexadecimal value that sets the control’s style.

See Also Accelerator Editor, Binary Data Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Dialog Editor Tips (Specific to Visual C++)

Home | Overview | How Do I

For information about the dialog editor’s capabilities in general, see the dialog editor topics in the Visual C++ User’s Guide.

This group of topics covers dialog editor capabilities that apply only to Visual C++.

What do you want to know more about?

  • Editing the properties of multiple controls together

  • Arranging pushbuttons along the right or bottom of the dialog box

  • Searching across dialog boxes

See Also Accelerator Editor, Binary Data Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Editing the Properties of Multiple Controls Together

Home | Overview | How Do I

In the dialog editor, you can select multiple controls and open a property page for all of them by clicking Properties on the View menu. The changes you make on this page are reflected in all the controls you selected.

If you make a mistake, choose Undo from the Edit menu. A single undo will correct the mistake for all the controls.

See Also Accelerator Editor, Binary Data Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Arranging Pushbuttons in a Dialog Box

Home | Overview | How Do I

In the dialog editor, you can arrange the pushbuttons in a dialog box in either of two standard locations, as recommended by the User Interface Guidelines for Microsoft Windows:

  • Along the right edge of the dialog box, beginning in the upper right corner

  • Along the bottom edge of the dialog box, right-justified to the bottom right corner.

To arrange push buttons along the right or bottom of the dialog box

  1. Select one or more push buttons.

  2. From the Layout menu, choose Arrange Buttons, and then choose one of the following arrangements:
    • Right: aligns push buttons along the right edge of the dialog box.

    • Bottom: aligns push buttons along the bottom edge of the dialog box.

    If you select a control other than a push button, its position is not affected.

See Also Accelerator Editor, Binary Data Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Searching Across Dialog Boxes

Home | Overview | How Do I

While using the dialog editor, you can use the Find command to search for labels for static text controls, multiple instances of the same word across dialog boxes, or to find a dialog box in a long list. The Find command helps when you need to make changes in dialog boxes, or when you need to check consistency, or when you can remember the contents of a dialog but not its ID. You can also search for control or dialog IDs, if you remember the ID but not the contents.

To find control labels or IDs

  1. From the Edit menu, choose Find.

  2. In the Find what box, select a previous search string from the drop-down list, type the label or ID you want to find, or type a regular expression to match a pattern.

Tip Click the button to the right of the Find what box to display a list of regular search expressions. When you select an expression from this list, it is substituted as the search text in the Find what box. If you use regular expressions, be sure the Regular expression check box is selected.

  3. Select any of the Find options.

  4. Click Find Next.

See Also Accelerator Editor, Binary Data Editor, Graphics Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Graphics Editor Topics for Visual C++

Home | Overview | How Do I

For Visual C++ projects, use the graphics editor to edit graphical images, including bitmaps, icons (including 48 x 48-pixel icons), and cursors.

What do you want to know more about?

  • Icons and cursors

  • Creating or editing icons and cursors

  • Selecting or customizing a display device

  • Drawing with screen and inverse colors

  • Creating a 256-color icon or cursor

  • Setting a cursor’s hot spot

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Icons and Cursors

Home | Overview | How Do I

Icons and cursors are like images, and you edit them in the same ways. However, icons and cursors have attributes that distinguish them from images. For example, each icon or cursor resource can contain multiple images for different display devices. In addition, a cursor has a “hot spot”: the location Windows uses to track its position.

When you create a new icon or cursor, the Graphics editor first creates an image for VGA. The image is initially filled with the “screen” (transparent) color. If the image is a cursor, the hot spot is initially the upper-left corner (coordinates 0,0).

By default, the graphics editor supports the creation of images for the devices shown in the following table.

Devices | Colors | Width (pixels) | Height (pixels)
Monochrome | 2 | 32 | 32
Small | 16 | 16 | 16
Normal | 16 | 32 | 32
Large | 256 | 64 | 64

You can create images for other devices by typing width, height, and color-count parameters into the Custom Device dialog box.

What do you want to do?

  • Create or edit an icon or cursor

  • Select or customize a display device

  • Draw with screen and inverse colors

  • Create a 256-color icon or cursor

  • Set a cursor’s hot spot

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Creating or Editing Icons and Cursors

Home | Overview | How Do I

Use the graphics editor to create and edit icons and cursors.

What do you want to know more about?

  • Icons and Cursors

  • Selecting or customizing a display device

  • Drawing with screen and inverse colors

  • Creating a 256-color icon or cursor

  • Setting a cursor’s hot spot

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Selecting or Customizing a Display Device

Home | Overview | How Do I

When you create a new icon or cursor image with the graphics editor, you need to designate the target display device. When the icon or cursor resource is opened, the image most closely matching the current display device is opened by default.

In addition to the standard types of devices listed, you can add a custom device for your icon or cursor image. You can enter width, height, and color-count parameters in the Custom Image dialog box.

To select a target device image

  1. On the control bar of the Image editor window, click the New Device Image button.

  2. Select a target device image from the list box.

    – or –

    Choose the Custom button to define the width, height, and colors of a custom image.

  3. Click OK to select the new parameters.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Drawing with Screen and Inverse Colors

Home | Overview | How Do I

In the graphics editor, the initial icon or cursor image has a transparent attribute. Although icon and cursor images are rectangular, many do not appear so because parts of the image are transparent: the underlying image on the screen shows through the icon or cursor. When you drag an icon, parts of the image may appear in an inverted color. You create this effect by choosing screen-color and inverse-color options from the color indicator on the Colors palette.

The screen and inverse colors you apply to icons and cursors either shape and color the derived image or designate inverse regions. The colors indicate parts of the image possessing those attributes. You can change the colors that represent the screen-color and inverse-color attributes in editing. These changes do not affect the appearance of the icon or cursor in your application.

To create transparent or inverse regions

  1. On the Colors palette, click a selector for screen or inverse color.

  2. Apply the screen or inverse color.

To change the screen or inverse color

  1. Select either the screen-color selector or the inverse-color selector.

  2. Choose a color from the Colors palette.

    The complementary color is automatically designated for the other selector.

Tip If you double-click the screen color or inverse-color indicator, the Custom Color Selector dialog box appears.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Creating a 256-Color Icon or Cursor

Home | Overview | How Do I

Using the graphics editor, icons can be sized large (64 x 64) with a 256-color palette to choose from. To draw with a selection from the 256-color palette, you need to display the palette in the property page for the icon or cursor and select the colors from the property page.

To choose a color from the 256-color palette for large icons

  1. Select the large icon or cursor, or create a new large icon or cursor.

  2. On the View menu, click Properties. Select the Palette tab.

  3. Choose the color from the 256 colors displayed in the palette.

The initial palette used for 256-color images matches the palette returned by the CreateHalftonePalette() Windows API. All icons intended for the Windows shell should use this palette to prevent flicker during palette realization.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Setting a Cursor's Hot Spot

Setting a Cursor’s Hot Spot

Home | Overview | How Do I

The hot spot of a cursor is the point to which Windows refers in tracking the cursor’s position. By default, the hot spot is set to the upper-left corner (coordinates 0,0). The Cursor Properties page and the graphics editor control bar show the hot spot coordinates.

To set a cursor’s hot spot

  1. On the control bar of the Image editor window, choose the Hot Spot button.

  2. Click the pixel you want to designate as the cursor’s hot spot.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Menu Editor Topics for Visual C++

Home | Overview | How Do I

For Visual C++ projects, use the Menu editor to edit your program’s menus, including pop-up menus.

For MFC programs, you can use ClassWizard to hook menu items to code. Double-click the menu item in the menu editor to open ClassWizard.

What do you want to know more about?

  • Learn more about working with menus

  • Use the menu editor to create and edit menus, in general

  • Create a pop-up menu

  • View the menu resource as a pop-up menu

  • Associate a menu item with an accelerator key

  • Associate a menu item with a status bar prompt

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, String Editor, Toolbar Editor, Version Editor


Creating Pop-up Menus

Home | Overview | How Do I

Pop-up menus (also known as shortcut menus) display frequently-used commands with a right mouse click. They can be context sensitive to the location of the pointer. Using pop-up menus in your application requires building the menu itself and then connecting it to application code.

Once you have created the menu resource, your application code needs to load the menu resource and use the TrackPopupMenu command to cause the menu to appear. Once the user has dismissed the pop-up menu by clicking outside it, or has clicked on a command, that function will return. If the user chooses a command, that command message will be sent to the window whose handle was passed.

What do you want to do?

  • Create a pop-up menu

  • Connect a pop-up menu to your application

To create a pop-up menu

  1. Create a menu bar with an empty title.

  2. Type a temporary letter in the caption or choose an attribute to reverse later. This enables the menu to be created.

  3. Move to the first menu item in the menu. Bring up the property page and type in the caption and any other information.

    Repeat this process for any other menu items in the pop-up menu.

  4. Make the top menu bar empty again by deleting the temporary letter in the caption or by resetting the temporary attribute.

    The goal is to have a pop-up menu descending beneath a blank menu bar.

  5. Save the menu resource.

To connect a pop-up menu to your application

  • Add the following code to your source file:
     CMenu menu;
 VERIFY(menu.LoadMenu(IDR_MENU1));
 CMenu* pPopup = menu.GetSubMenu(0);
 ASSERT(pPopup != NULL);

 pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, x, y, AfxGetMainWnd());

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Viewing the Menu Resource as a Pop-up Menu

Home | Overview | How Do I

Normally, when you are working in the menu editor, a menu resource is displayed as a menu bar. However, you might have menu resources that are added to the application’s menu bar while the program is running. To see what a menu resource looks like as a pop-up menu, use the menu editor’s View as Popup command on the right mouse pop-up menu. To change back to the menu-bar view, choose View as Popup again.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, String Editor, Toolbar Editor, Version Editor


Associating a Menu Item with an Accelerator Key

Home | Overview | How Do I

Many times, you want a menu item and a keyboard combination to issue the same program command. You do this by using the menu editor to assign the same resource identifier to the menu item and to an entry in your application’s accelerator table. You then edit the menu item’s caption to show the name of the accelerator key.

To associate a menu item with an accelerator key

  1. In the menu editor, select the menu item you want. From the View menu, choose Properties or double-click the item.

  2. In the Caption box, add the name of the accelerator key to the menu caption:
    • Following the menu caption, type the escape sequence for a tab (\t), so that all the menu’s accelerator keys are left-aligned.

    • Type the name of the modifier key (CTRL, ALT, or SHIFT) followed by a plus sign (+) and the name, letter, or symbol of the additional key.

    For example, to assign CTRL+O to the Open command on the File menu, you modify the menu item’s caption so that it looks like this:

    Open\tCtrl+O

    The menu item in the Menu editor is updated to reflect the new caption as you type it.

  3. Create the accelerator-table entry in the accelerator editor and assign it the same identifier as the menu item. Use a key combination that you think will be easy to remember.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, String Editor, Toolbar Editor, Version Editor


Associating a Menu Item with a Status Bar Prompt

Home | Overview | How Do I

Your application can display descriptive text for each of the menu items that may be selected. MFC can handle this for you if you have a string in the string table whose ID is the same as the command. You do this by assigning a text string to each menu item using the Menu Item property page.

To associate a menu item with a status bar text string

  1. Click the right mouse button on the menu item and select Properties.

  2. In the Prompt box, type the associated status bar text.

Note This feature is only available with the Microsoft Foundation Class Library (MFC).

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor, Version Editor


Symbol Editor Topics

Home | Overview | How Do I

A symbol is a resource identifier that consists of a text string (name) mapped to an integer value — for example:

IDC_EDITNAME = 5100

Symbols provide a descriptive way of referring to resources and user-interface objects, both in your source code and while you’re working with them in the resource editors.

You can view and manipulate symbols in one convenient place using the Resource Symbols browser, also known as the Symbol Editor.

What do you want to do?

  • Learn about symbols

  • Learn about symbol name restrictions

  • Learn about symbol value restrictions

  • Change a symbol or symbol name

  • Change a symbol’s numerical value

  • Manage symbols with the Resource Symbols browser


Symbols

Home | Overview | How Do I

A symbol is a resource identifier that consists of a text string (name) mapped to an integer value. Symbols provide a descriptive way of referring to resources and user-interface objects, both in your source code and while you’re working with them in the resource editors.

When you create a new resource or resource object, the resource editors provide a default name for the resource (for example, IDC_RADIO1) and assign a value to it. The name-plus-value definition is stored in the Resource.h file.

Note When you are copying resources or resource objects from one .rc file to another, the transferred resource’s symbol value, or symbol name and value, might be changed to avoid conflicts with symbol names or values in the existing file.

What do you want to know more about?

  • Symbol name restrictions

  • Symbol value restrictions


Symbol Name Restrictions

Home | Overview | How Do I

All symbol names must be unique within the scope of the application. This prevents conflicting symbol definitions in the header files. Allowed characters for a symbol name include A-Z, a-z, 0-9, and underscores ( _ ). Symbol names cannot begin with a number and are limited to 247 characters. Symbol names are not case sensitive, but the case of the first symbol definition is preserved.

Symbol names can be used more than once in your application. For example, if you are writing a data-entry program with several dialog boxes containing a text box for a person’s Social Security number, you may want to give all the related text boxes a symbol name of IDC_SSN. To do this, you can define a single symbol and use it as many times as needed.

Although it is not required, symbol names are often given descriptive prefixes that indicate the kind of resource or object they represent. The Microsoft Foundation Class Library (MFC) uses the symbol naming conventions shown in the following table.

Category | Prefix | Use
Resources | IDR_ IDD_ IDC_ IDI_ IDB_ | Accelerator or menu (and associated resources) Dialog box Cursor Icon Bitmap
Menu items | IDM_ | Menu item
Commands | ID_ | Command
Controls and child windows | IDC_ | Control
Strings | IDS_ IDP_ | String in the string table String-table string used for message boxes


Symbol Value Restrictions

Home | Overview | How Do I

A symbol value can be any integer expressed in the normal manner for #define preprocessor directives. Here are some examples of symbol values:

18
4001
0x0012
-3456

Note Symbol values for resources (accelerators, bitmaps, cursors, dialog boxes, icons, menus, string tables, and version information) must be decimal numbers in the range from 0 to 32,767 (but cannot be hexadecimal). Symbol values for parts of resources (such as dialog box controls or individual strings in the string table) can be from 0 to 65,534 or from -32,768 to 32,767.

Some number ranges are used by the development environment and MFC for special purposes.

You cannot define a symbol value using other symbol strings. For example, the following symbol definition is not supported:

#define IDC_MYEDIT  IDC_OTHEREDIT  //not supported

You also cannot use preprocessor macros with arguments as value definitions. For example,

#define   IDD_ABOUT  ID(7) //not supported

is not a valid expression regardless of what ID evaluates to at compile time.

Your application may have an existing file containing symbols defined with expressions. For more information on how to include the symbols as read-only symbols, see Using Shared (Read Only) or Calculated Symbols.


Changing a Symbol or Symbol Name

Home | Overview | How Do I

When you create a new resource or resource object, the development environment assigns it a default name, for example, IDD_DIALOG1. Use the resource’s property page to change the default symbol name or to change the name of any symbol already associated with a resource.

To change a resource’s symbol name

  1. In ResourceView, select the resource.

  2. From the View menu, choose Properties to move directly to the resource’s property page.

  3. In the ID box, type a new symbol name or select from the list of existing symbols. If you type a new symbol name, it is automatically assigned a value.

You can use the Resource Symbols browser to change the names of symbols not currently assigned to a resource. For more information, see Changing Unassigned Symbols.


Changing a Symbol's Numerical Value

Home | Overview | How Do I

Usually you can let the development environment assign the numerical value associated with the symbol names you define. However, there may be times when you need to change the symbol value associated with a resource — for example, when you want a group of controls or a series of related strings in the string table to have sequential IDs.

For symbols already associated with a single resource, use the resource’s property page to change the symbol value. For symbols associated with more than one resource or object, make the changes directly in Resource.h using a text editor.

What do you want to do?

  • Change a symbol value assigned to a single resource

  • Change a symbol value assigned to multiple resources

To change a symbol value assigned to a single resource or object

  1. Select the resource.

  2. From the View menu, choose Properties.

  3. In the ID box, type the symbol name followed by an equal sign and an integer. For example:
     IDC_EDITNAME=5100

The new value is stored in the symbol header file the next time you save the project. Only the symbol name remains visible in the ID box; the equal sign and value are not displayed after they are validated.

To change the numeric value of a symbol assigned to more than one resource or object

  1. End your editing session by closing the current resource file.

  2. Open Resource.h in a source window and make the necessary changes.

  3. Save Resource.h. The next time you open the project’s .rc file, the new symbol values are used.

Note While editing Resource.h, take special care not to define duplicate symbols. The development environment can detect duplicates only of the symbols it creates.

You can use the Resource Symbols browser to change the value of symbols not currently assigned to a resource. For more information, see Changing Unassigned Symbols.


Managing Symbols with the Resource Symbols Browser

Home | Overview | How Do I

As your application grows in size and sophistication, so does the number of resources and symbols Tracking large numbers of symbols scattered throughout several files can be difficult. The Resource Symbols browser simplifies symbol management by offering a central tool through which you can:

  • Quickly browse existing symbol definitions to see the value of each symbol, a list of symbols being used, and the resources assigned to each symbol.

  • Create new symbols.

  • Change the name and value of a symbol that is not in use.

  • Delete a symbol if it is not being used.

  • Move quickly to the appropriate resource editor where the symbol is being used.

What do you want to do?

  • Open the Resource Symbols browser

  • Create new symbols

  • Change unassigned symbols

  • Open the Resource editor for a given symbol

To open the Resource Symbols browser

  • From the View menu, choose Resource Symbols.


Creating New Symbols

Home | Overview | How Do I

When you are beginning a new project, you may find it convenient to map out the symbol names you need before creating the resources they will be assigned to.

To create a new symbol using the Resource Symbols browser

  1. In the Resource Symbols browser, click New.

  2. In the Name box, type a symbol name.

  3. Accept the assigned symbol value or, in the Value box, type a new value.

  4. Click OK to add the new symbol to the symbol list.

  5. Click Close.

If you type a symbol name that already exists, a message box appears stating that a symbol with that name is already defined. You cannot define two or more symbols with the same name, but you can define different symbols with the same numeric value. For more information, see Symbol Name Restrictions and Symbol Value Restrictions.


Changing Unassigned Symbols

Home | Overview | How Do I

While in the Resource Symbols browser, you can edit or delete existing symbols that are not already assigned to a resource or object. You can change existing symbols that are in use in only one place by using the Change command to move to the appropriate resource’s property page or by moving to the property page directly. You cannot change read-only symbols.

A check mark in the In Use column of the Resource Symbols browser indicates that the symbol is being used. If Show read-only symbols is selected, read-only symbols are also displayed. Editable symbols are displayed as bold text, and read-only symbols are displayed as normal text. If a symbol is unassigned, “not used” appears in the Used by box when you select the symbol.

For more information on changing the name or value of a symbol already in use, see Changing a Symbol or Symbol Name.

To change an unassigned symbol using the Resource Symbols browser

  1. In the Name box, select the unassigned symbol you want, and click Change.

  2. Edit the symbol’s name or value in the boxes provided.

  3. Click OK.

To delete an unassigned symbol using the Resource Symbols browser

  • Select the unassigned symbol that you want to delete, and click Delete.

Note Before deleting an unused symbol in a resource file, make sure it is not used elsewhere in the program or by resource files included at compile time.


Opening the Resource Editor for a Given Symbol

Home | Overview | How Do I

When you are browsing symbols in the Resource Symbols browser, you may want more information on how a particular symbol is used. The View Use command provides a quick way to get this information.

To move to the resource editor where a symbol is being used

  1. In the Name box of the Resource Symbols browser, select the symbol you want.

  2. In the Used By box, select the resource type that interests you.

  3. Click the View Use button.

    The resource appears in the appropriate editor window.


Changing the Name of the Symbol Header File

Home | Overview | How Do I

Normally all symbol definitions are saved in Resource.h. However, you may need to change this include filename so that you can, for example, work with more than one resource file in the same directory.

To change the name of the resource symbol header file

  1. From the View menu, choose Resource Includes.

  2. In the Symbol header file box, type the new name for the include file.


Using Shared (Read-Only) or Calculated Symbols

Home | Overview | How Do I

The first time the development environment reads a resource file created by another application, it marks all included header files as read-only. Subsequently, you can use the Resource Includes command on the View menu to add additional read-only symbol header files.

One reason you may want to use read-only symbol definitions is for symbol files that you plan to share among several projects.

You would also use included symbol files when you have existing resources with symbol definitions that use expressions rather than simple integers to define the symbol value. For example,

#define   IDC_CONTROL1 2100
#define   IDC_CONTROL2 (IDC_CONTROL1+1)

The environment will correctly interpret these calculated symbols as long as:

  • The calculated symbols are placed in a read-only symbols file.

  • Your resource file contains resources to which these calculated symbols are already assigned.

To include shared (read-only) symbols in your resource file

  1. From the View menu, choose Resource Includes.

  2. In the Read-only symbol directives box, use the #include compiler directive to specify the file where you want the read-only symbols to be kept. (You should not call the file Resource.h, since that is the filename normally used by the main symbol header file.)

    Important What you type in the Read-Only Symbol Directives box is included in the resource file exactly as you type it. Make sure what you type does not contain any spelling or syntax errors.

    You should use the Read-only symbol directives box to include files with symbol definitions only. Do not include resource definitions; otherwise, duplicate resource definitions will be created when the file is saved.

  3. Place the symbols in the file you specified.

    The symbols in files included in this way are evaluated each time you open your resource file, but they are not replaced on the disk when you save your file.

  4. Click OK.


Version Editor Topics

Home | Overview | How Do I

With the Version Information editor, you can add or delete string blocks, search for string blocks, and modify individual string values in a version resource.

A version information resource has a single fixed information block at the top and one or more string information blocks at the bottom. The top block has both editable numeric boxes and selectable drop-down lists. The bottom string block has editable text boxes.

You can sort the information sequence of the string block by clicking either the Key or the Value buttons. These buttons automatically rearrange the information into the selected sequence.

What do you want to do?

  • Edit a version information resource

  • Add a new string block

  • Delete a string block

  • Find a string block

To edit a version information resource

  • Double-click the item you want to edit, and make the changes.

To add a new string block

  1. Open a version information resource.

  2. From the Insert menu, choose New Version Info Block.

    This command appends an additional string information block into the current version information resource and opens the Block Header properties page.

  3. On the Block Header properties page, choose the appropriate language and character set for the new block.

To delete a string block

  1. With a version information resource open, select one of the block headers.

  2. From the Insert menu, choose Delete Version Info Block.

    This command deletes the selected header and leaves the remaining version information intact.

To find a string block

  1. From the Edit menu, choose Find.

  2. In the Find what box, select a previous search string from the drop-down list, type the string you want to find, or type a regular expression to match a pattern.

Tip Click the button to the right of the Find what box to display a list of regular search expressions. When you select an expression from this list, it is substituted as the search text in the Find what box. If you use regular expressions, be sure the Regular expression check box is selected.

  3. Select any of the Find options.

  4. Click Find Next.

See Also Accelerator Editor, Binary Data Editor, Dialog Editor, Menu Editor, String Editor, Toolbar Editor


Status Bar Topics

Home | Overview | How Do I | Tutorial

Status bars give your application a place to display messages and useful information to the user without interrupting the user’s work. Typically displayed at the bottom of a window, status bars have “panes,” which include “indicators” and a ”message line.” The indicators give the status of such things as SCROLL LOCK, whether macro recording is turned on, and so on. The message line on the status bar can display information about program status or about a toolbar button or menu item that the user is pointing to with the mouse.

What do you want to know more about?

  • Status bar implementation in MFC

  • The relationship between MFC and the status bar common control

  • Status bars as a kind of control bar

  • What a status bar looks like

  • Updating the text of a status bar pane


Status Bars

Home | Overview | How Do I | Tutorial

A CStatusBar object is a control bar with a row of text output panes. The output panes are commonly used as message lines and as status indicators. Examples include the menu help-message lines that briefly explain the selected menu command and the indicators that show the status of the SCROLL LOCK, NUM LOCK, and other keys.

As of MFC version 4.0, status bars are implemented using class CStatusBarCtrl, which encapsulates a Windows 95 status bar control. For backward compatibility, MFC retains the older status bar implementation in class COldStatusBar. The documentation for earlier versions of MFC describes COldStatusBar under CStatusBar.

CStatusBar::GetStatusBarCtrl, a member function new to MFC 4.0, allows you to take advantage of the Windows common control’s support for status bar customization and additional functionality. CStatusBar member functions give you most of the functionality of the Windows common controls; however, when you call GetStatusBarCtrl, you can give your status bars even more of the characteristics of a Windows 95 status bar. When you call GetStatusBarCtrl, it will return a reference to a CStatusBarCtrl object. You can use that reference to manipulate the status bar control.

The following figure shows a status bar that displays several indicators.

A Status Bar

Like the toolbar, the status-bar object is embedded in its parent frame window and is constructed automatically when the frame window is constructed. The status bar, like all control bars, is destroyed automatically as well.

What do you want to know more about?

  • Updating status bar panes

  • MFC classes CStatusBar and CStatusBarCtrl

  • An example of using a status bar

  • Control bars

  • Dialog bars

  • Toolbars


Status Bars: Updating the Text of a Status-Bar Pane

Home | Overview | How Do I | Tutorial

This article explains how to change the text that appears in an MFC status bar pane. A status bar — a window object of class CStatusBar — contains several “panes.” Each pane is a rectangular area of the status bar that you can use to display information. For example, many applications display the status of the CAPS LOCK, NUM LOCK, and other keys in the rightmost panes. Applications also often display informative text in the leftmost pane (pane 0), sometimes called the “message pane.” For example, the default MFC status bar uses the message pane to display a string explaining the currently selected menu item or toolbar button. The figure in Status Bars shows a status bar from an AppWizard-created MFC application.

By default, MFC does not enable a CStatusBar pane when it creates the pane. To activate a pane, you must use the ON_UPDATE_COMMAND_UI macro for each pane on the status bar and update the panes. Because panes do not send WM_COMMAND messages (they aren’t like toolbar buttons), you can’t use ClassWizard to create an update handler to activate a pane; you must type the code manually.

For example, suppose one pane has ID_INDICATOR_PAGE as its command identifier and that it contains the current page number in a document. The following procedure describes how to create a new pane in the status bar.

To make a new pane

  1. Define the pane’s command ID.

    Open the ResourceView in the Project Workspace window. Open the Symbol Browser with the Resource Symbols command on the View menu, and click New. Type a command ID name: for example, ID_INDICATOR_PAGE. Specify a value for the ID, or accept the value suggested by the Symbol Browser. For example, for ID_INDICATOR_PAGE, accept the default value. Close the Symbol Browser.

  2. Define a default string to display in the pane.

    With the ResourceView open, double-click String Table in the window that lists resource types for your application. With the String Table editor open, choose New String from the Insert menu. In the String Properties window, select your pane’s command ID (for example, ID_INDICATOR_PAGE) and type a default string value, such as “Page ”. Close the string editor. (You need a default string to avoid a compiler error.)

  3. Add the pane to the indicators array.

    In file MAINFRM.CPP, locate the indicators array. This array lists command IDs for all of the status bar’s indicators, in order from left to right. At the appropriate point in the array, enter your pane’s command ID, as shown here for ID_INDICATOR_PAGE:

    static UINT BASED_CODE indicators[] =
{
    ID_SEPARATOR,           // status line indicator
    ID_INDICATOR_CAPS,
    ID_INDICATOR_NUM,
    ID_INDICATOR_SCRL,
    ID_INDICATOR_PAGE,
};

The recommended way to display text in a pane is to call the SetText member function of class CCmdUI in an update handler function for the pane. For example, you might want to set up an integer variable m_nPage that contains the current page number and use SetText to set the pane’s text to a string version of that number.

Note The SetText approach is recommended. It is possible to perform this task at a slightly lower level by calling the CStatusBar member function SetPaneText. Even so, you still need an update handler. Without such a handler for the pane, MFC automatically disables the pane, erasing its content.

The following procedure shows how to use an update handler function to display text in a pane.

To make a pane display text

  1. Add a command update handler for the command.

    You can’t use ClassWizard to write a handler for a status bar pane, so manually add a prototype for the handler, as shown here for ID_INDICATOR_PAGE (in MAINFRM.H):

    afx_msg void OnUpdatePage(CCmdUI *pCmdUI);

    In the appropriate .CPP file, add the handler’s definition, as shown here for ID_INDICATOR_PAGE (in MAINFRM.CPP):

    void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
{
    pCmdUI->Enable();
}

    In the appropriate message map, add the ON_UPDATE_COMMAND_UI macro (outside the “{{AFX” comments), as shown here for ID_INDICATOR_PAGE (in MAINFRM.CPP):

    ON_UPDATE_COMMAND_UI(ID_INDICATOR_PAGE, OnUpdatePage)
  2. Add code to the handler to display your text.

    For ID_INDICATOR_PAGE, expand the OnUpdatePage handler from step 1 above, adding the last three lines:

    void CMainFrame::OnUpdatePage(CCmdUI *pCmdUI)
{
    pCmdUI->Enable();
    CString strPage;
    strPage.Format( "Page %d", m_nPage );
    pCmdUI->SetText( strPage );
}

Once you define the value of the m_nPage member variable (of class CMainFrame), this technique causes the page number to appear in the pane during idle processing in the same manner that the application updates other indicators. If m_nPage changes, the display changes during the next idle loop.

What do you want to know more about?

  • Updating user-interface objects, such as toolbar buttons and menu items, as program conditions change

See Also CStatusBar


Tool Tip Topics

Home | Overview | How Do I

The procedures are distinct for adding tool tips to controls contained in windows derived from MFC class CFrameWnd and windows not derived from CFrameWnd.

What do you want to know more about?

Tool tips for controls in a window that is:

  • Derived from CFrameWnd

  • Not derived from CFrameWnd


Tool Tips

Home | Overview | How Do I

This article family covers enabling tool tips for controls contained in a window that is not derived from CFrameWnd. The article Toolbars: Tool Tips provides information about tool tips for controls in a CFrameWnd.

Topics covered in this article family include:

  • Enabling Tool Tips

  • Handling TTN_NEEDTEXT Notification for Tool Tips

  • The TOOLTIPTEXT Structure

Tool tips are automatically displayed for buttons and other controls contained in a parent window derived from CFrameWnd. This is because CFrameWnd has a default handler for the TTN_GETDISPINFO notification, which handles TTN_NEEDTEXT notifications from tool tip controls associated with controls.

However, this default handler is not called when the TTN_NEEDTEXT notification is sent from a tool tip control associated with a control in a window that is not a CFrameWnd, such as a control on a dialog box or a form view. Therefore, it is necessary for you to provide a handler function for the TTN_NEEDTEXT notification message in order to display tool tips for child controls.

The default tool tips provided for your windows by CWnd::EnableToolTips do not have text associated with them. To retrieve text for the tool tip to display, the TTN_NEEDTEXT notification is sent to the tool tip control's parent window just before the tool tip window is displayed. If there is no handler for this message to assign some value to the pszText member of the TOOLTIPTEXT structure, there will be no text displayed for the tool tip.


Enabling Tool Tips

Home | Overview | How Do I

You can enable tool tip support for the child controls of a window (such as the controls on a form view or dialog box).

To enable tool tips for the child controls of a window

  1. Call EnableToolTips for the window for which you want to provide tool tips.

  2. Provide a string for each control in your TTN_NEEDTEXT notification handler. The handler is in the message map of the window that contains the child controls (for example, your form view class). This handler should call a function that identifies the control and sets pszText to specify the text used by the tool tip control.


Handling TTN_NEEDTEXT Notification for Tool Tips

Home | Overview | How Do I

As part of enabling tool tips, you handle the TTN_NEEDTEXT message by adding the following entry to your owner window’s message map:

ON_NOTIFY_EX( TTN_NEEDTEXT, 0, memberFxn )

memberFxn

The member function to be called when text is needed for this button.

Note that the ID of a tool tip is always 0.

Declare your handler function in the class definition as follows:

BOOL CMyClass::memberFxn( UINT id, NMHDR * pTTTStruct, LRESULT * pResult );

where the italicized parameters are:

  • id Identifier of the control that sent the notification. Not used. The control id is taken from the NMHDR structure.

  • pTTTStruct A pointer to the NMTTDISPINFO structure. This structure is also discussed further in The TOOLTIPTEXT Structure.

  • pResult A pointer to result code you can set before you return. TTN_NEEDTEXT handlers can ignore the pResult parameter.

As an example of a form-view notification handler:

BOOL CMyFormView::OnToolTipNotify( UINT id, NMHDR * pNMHDR, LRESULT * pResult );
{
    TOOLTIPTEXT *pTTT = (TOOLTIPTEXT *)pNMHDR;
    UINT nID =pNMHDR->idFrom;
    if (pTTT->uFlags & TTF_IDISHWND)
    {
        // idFrom is actually the HWND of the tool
        nID = ::GetDlgCtrlID((HWND)nID);
        if(nID)
        {
            pTTT->lpszText = MAKEINTRESOURCE(nID);
            pTTT->hinst = AfxGetResourceHandle();
            return(TRUE);
        }
    }
    return(FALSE);
}
void CTestView::OnInitialUpdate()
{
    CMyFormView::OnInitialUpdate();
    EnableToolTips(TRUE);
}


The TOOLTIPTEXT Structure

Home | Overview | How Do I

In writing your tool tip notification handler, you need to use the TOOLTIPTEXT structure. The members of the TOOLTIPTEXT structure are:

typedef struct {
    NMHDR     hdr;        // required for all WM_NOTIFY messages
    LPTSTR    lpszText;   // see below
    WCHAR     szText[80]; // buffer for tool tip text
    HINSTANCE hinst;      // see below
    UINT      uflags;     // flag indicating how to interpret the
                          // idFrom member of the NMHDR structure
                          // that is included in the structure
} TOOLTIPTEXT, FAR *LPTOOLTIPTEXT;

hdr

Identifies the tool that needs text. The only member of this structure you might need is the control’s command ID. The control’s command ID will be in the idFrom member of the NMHDR structure, accessed with the syntax hdr.idFrom. See NMHDR for a discussion of members of the NMHDR structure.

lpszText

Address of a string to receive the text for a tool.

szText

Buffer that receives the tool tip text. An application can copy the text to this buffer as an alternative to specifying a string address.

hinst

Handle of the instance that contains a string resource to be used as the tool tip text. If lpszText is the address of the tool tip text, this member is NULL.

When you handle the TTN_NEEDTEXT notification message, specify the string to be displayed in one of the following ways:

  • Copy the text to the buffer specified by the szText member.

  • Copy the address of the buffer that contains the text to the lpszText member.

  • Copy the identifier of a string resource to the lpszText member, and copy the handle of the instance that contains the resource to the hinst member.


Toolbar Topics

Home | Overview | How Do I | Sample | Tutorial

The toolbar family of articles describes MFC toolbars and how to create and use them.

What do you want to know more about?

  • Toolbar fundamentals

  • The MFC toolbar implementation

  • The toolbar bitmap

  • Sample toolbar code

  • Editing the toolbar resource

  • Updating the enabled/disabled state of toolbar buttons

  • Working with the toolbar control underlying an MFC toolbar

  • Docking and floating toolbars

  • Dynamically resizing a toolbar

  • Toolbar tool tips

  • Flyby status bar updates

  • The CToolBar and CToolBarCtrl classes

  • Multiple toolbars

  • Using your old toolbars

  • Status bars

  • Control bars

  • Dialog bars

See Also Toolbar Editor


Toolbars

Home | Overview | How Do I | Sample | Tutorial

Toolbars display a collection of easy-to-use buttons that represent commands. AppWizard makes it easy to add a toolbar to your application. The following are introduced in this article:

  • Toolbar buttons

  • Docking and floating toolbars

  • Toolbars and tool tips

  • The CToolBar and CToolBarCtrl classes

  • The Toolbar bitmap

Toolbar Buttons

The buttons in a toolbar are analogous to the items in a menu. Both kinds of user-interface objects generate commands, which your program handles by providing handler functions. Often toolbar buttons duplicate the functionality of menu commands, providing an alternative user interface to the same functionality. Such duplication is arranged simply by giving the button and the menu item the same ID.

You can make the buttons in a toolbar appear and behave as pushbuttons, check boxes, or radio buttons. For more information, see class CToolBar.

Docking and Floating Toolbars

An MFC toolbar can:

  • Remain stationary along one side of its parent window.

  • Be dragged and “docked,” or attached, by the user to any side or sides of the parent window you specify.

  • Be “floated,” or detached from the frame window, in its own mini-frame window so the user can move it around to any convenient position.

  • Be resized while floating.

For more information, see the article Toolbars: Docking and Floating.

Toolbars and Tool Tips

MFC toolbars can also be made to display “tool tips” — tiny popup windows containing a short text description of a toolbar button’s purpose. As the user moves the mouse over a toolbar button, the tool tip window pops up to offer a hint. For more information, see the article Toolbars: Tool Tips.

The CToolBar and CToolBarCtrl Classes

You manage your application’s toolbars via class CToolBar. As of MFC version 4.0, CToolBar has been reimplemented to use the toolbar common control available under Windows 95 and Windows NT version 3.51 or later.

This reimplementation results in less MFC code for toolbars, because MFC makes use of operating system support. The reimplementation also improves capability. You can use CToolBar member functions to manipulate toolbars, or you can obtain a reference to the underlying CToolBarCtrl object and call its member functions for toolbar customization and additional functionality.

Tip If you have invested heavily in the older MFC implementation of CToolBar, that support is still available. See the article Toolbars: Using Your Old Toolbars.

Also see the MFC General sample DOCKTOOL.

The Toolbar Bitmap

Once constructed, a CToolBar object creates the toolbar image by loading a single bitmap that contains one image for each button. AppWizard creates a standard toolbar bitmap that you can customize with the Visual C++ toolbar editor.

What do you want to know more about?

  • Toolbar fundamentals

  • Docking and floating toolbars

  • Toolbar tool tips

  • The CToolBar and CToolBarCtrl classes

  • Status bars

  • Control bars

  • Dialog bars

See Also Toolbar Editor


Toolbars: Fundamentals

Home | Overview | How Do I | Sample | Tutorial

This article describes the fundamental MFC implementation that lets you add a default toolbar to your application by selecting an option in AppWizard. Topics covered include:

  • AppWizard toolbar option

  • The toolbar in code

  • Editing the toolbar resource

  • Multiple toolbars

The AppWizard Toolbar Option

To get a single toolbar with default buttons, select the Dockable Toolbar option on the page labeled AppWizard Step 4 of 6. This adds code to your application that:

  • Creates the toolbar object.

  • Manages the toolbar, including its ability to dock or to float.

The Toolbar in Code

The toolbar object is a CToolBar object declared as a data member of your application’s CMainFrame class. In other words, the toolbar object is embedded in the main frame window object. This means that MFC creates the toolbar when it creates the frame window and destroys the toolbar when it destroys the frame window. The following partial class declaration, for a multiple document interface (MDI) application, shows data members for an embedded toolbar and an embedded status bar. It also shows the override of the OnCreate member function.

class CMainFrame : public CMDIFrameWnd
{
   // ...

// Implementation
   // ...

protected:  // control bar embedded members
   CStatusBar  m_wndStatusBar;
   CToolBar    m_wndToolBar;

// Generated message map functions
protected:
   //{{AFX_MSG(CMainFrame)
   afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
      // NOTE - the ClassWizard will add and remove member functions here.
      // DO NOT EDIT what you see in these blocks of
      // generated code!
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};

Toolbar creation occurs in CMainFrame::OnCreate. MFC calls OnCreate after creating the Windows window for the frame but before the frame window becomes visible. The default OnCreate that AppWizard generates does the following toolbar tasks:

  1. Calls the CToolBar object’s Create member function to create the underlying CToolBarCtrl object.

  2. Calls LoadToolBar to load the toolbar resource information.

  3. Calls functions to enable docking, floating, and tool tips. For details about these calls, see the article Toolbars: Docking and Floating.

Note The MFC General sample DOCKTOOL includes illustrations of both old and new MFC toolbars. The toolbars that use COldToolbar require calls in step 2 to LoadBitmap (rather than LoadToolBar) and to SetButtons. The new toolbars require calls to LoadToolBar. Click for a list of MFC samples related to toolbars.

The docking, floating, and tool tips calls are optional. You can remove those lines from OnCreate if you prefer. The result is a toolbar that remains fixed, unable to float or redock and unable to display tool tips.

Editing the Toolbar Resource

The default toolbar you get with AppWizard is based on an RT_TOOLBAR custom resource, introduced in MFC version 4.0. You can edit this resource with the toolbar editor. The editor lets you easily add, delete, and rearrange buttons. It contains a graphical editor for the buttons that is very similar to the general graphics editor in Visual C++. If you edited toolbars in previous versions of Visual C++, you’ll find the task much easier now.

To connect a toolbar button to a command, you give the button a command ID, such as ID_MYCOMMAND. Specify the command ID in the button’s property page in the toolbar editor. Then use ClassWizard to create a handler function for the command.

New CToolBar member functions work with the RT_TOOLBAR resource. LoadToolBar now takes the place of LoadBitmap to load the bitmap of the toolbar button images, and SetButtons to set the button styles and connect buttons with bitmap images.

For details about the toolbar editor, see the Toolbar Editor overview in the Visual C++ User’s Guide.

Multiple Toolbars

AppWizard gives you one toolbar. If you want more, model your code for the additional toolbars on the code for the first one.

If you want to display a toolbar as the result of a command, you’ll need to:

  • Create a new toolbar resource with the toolbar editor and load it in OnCreate with the LoadToolbar member function.

  • Embed a new CToolBar object in your main frame window class.

  • Make the appropriate function calls in OnCreate to dock or float the toolbar, set its styles, and so on.

What do you want to know more about?

  • General information about toolbars

  • Docking and floating toolbars

  • Toolbar tool tips

  • The CToolBar and CToolBarCtrl classes

  • Working with the toolbar control

  • Using your old toolbars


Toolbars: Docking and Floating

Home | Overview | How Do I | Sample | Tutorial

The Microsoft Foundation Class Library supports dockable toolbars. A dockable toolbar can be attached, or docked, to any side of its parent window, or it can be detached, or floated, in its own mini-frame window. This article explains how to use dockable toolbars in your applications.

If you use AppWizard to generate the skeleton of your application, you are asked to choose whether you want dockable toolbars. By default, AppWizard generates the code that performs the three actions necessary to place a dockable toolbar in your application:

  • Enable docking for the frame window.

  • Enable docking for the toolbar.

  • Dock the toolbar to the frame window.

If any of these steps are missing, your application will display a standard toolbar. The last two steps must be performed for each dockable toolbar in your application.

Other topics covered in this article include:

  • Floating the toolbar

  • Dynamically resizing the toolbar

  • Setting wrap positions for a fixed-style toolbar

See the MFC General sample DOCKTOOL for examples.

Enabling Docking in a Frame Window

To dock toolbars to a frame window, the frame window (or destination) must be enabled to allow docking. This is done using the CFrameWnd::EnableDocking function, which takes one DWORD parameter that is a set of style bits indicating which side of the frame window accepts docking. If a toolbar is about to be docked and there are multiple sides that it could be docked to, the sides indicated in the parameter passed to EnableDocking are used in the following order: top, bottom, left, right. If you want to be able to dock control bars anywhere, pass CBRS_ALIGN_ANY to EnableDocking.

Enabling Docking for a Toolbar

After you have prepared the destination for docking, you must prepare the toolbar (or source) in a similar fashion. Call CControlBar::EnableDocking for each toolbar you want to dock, specifying the destination sides to which the toolbar should dock. If none of the sides specified in the call to CControlBar::EnableDocking match the sides enabled for docking in the frame window, the toolbar cannot dock — it will float. Once it has been floated, it remains a floating toolbar, unable to dock to the frame window.

If the effect you want is a permanently floating toolbar, call EnableDocking with a parameter of 0. Then call CFrameWnd::FloatControlBar. The toolbar remains floating, permanently unable to dock anywhere.

Docking the Toolbar

The framework calls CFrameWnd::DockControlBar when the user attempts to drop the toolbar on a side of the frame window that allows docking.

In addition, you can call this function at any time to dock control bars to the frame window. This is normally done during initialization. More than one toolbar can be docked to a particular side of the frame window.

Floating the Toolbar

Detaching a dockable toolbar from the frame window is called floating the toolbar. Call CFrameWnd::FloatControlBar to do this. Specify the toolbar to be floated, the point where it should be placed, and an alignment style that determines whether the floating toolbar is horizontal or vertical.

The framework calls this function when a user drags a toolbar off its docked location and drops it in a location where docking is not enabled. This can be anywhere inside or outside the frame window. As with DockControlBar, you can also call this function during initialization.

The MFC implementation of dockable toolbars does not provide some of the extended features found in some applications that support dockable toolbars. Features such as customizable toolbars are not provided.

Dynamically Resizing the Toolbar

As of Visual C++ version 4.0, you can make it possible for users of your application to resize floating toolbars dynamically. Typically, a toolbar has a long, linear shape, displayed horizontally. But you can change the toolbar’s orientation and its shape. For example, when the user docks a toolbar against one of the vertical sides of the frame window, the shape changes to a vertical layout. It’s also possible to reshape the toolbar into a rectangle with multiple rows of buttons.

You can:

  • Specify dynamic sizing as a toolbar characteristic.

  • Specify fixed sizing as a toolbar characteristic.

To provide this support, there are two new toolbar styles for use in your calls to the CToolBar::Create member function. They are

  • CBRS_SIZE_DYNAMIC Control bar is dynamic.

  • CBRS_SIZE_FIXED Control bar is fixed.

The size dynamic style lets your user resize the toolbar while it is floating, but not while it is docked. The toolbar “wraps” where needed to change shape as the user drags its edges.

The size fixed style preserves the wrap states of a toolbar, fixing the position of the buttons in each column. Your application’s user can’t change the shape of the toolbar. The toolbar wraps at designated places, such as the locations of separators between the buttons. It maintains this shape whether the toolbar is docked or floating. The effect is a fixed palette with multiple columns of buttons.

You can also use CToolBar::GetButtonStyle to return a state and style for buttons on your toolbars. A button’s style determines how the button appears and how it responds to user input; the state tells whether the button is in a wrapped state.

Setting Wrap Positions for a Fixed-Style Toolbar

For a toolbar with the size fixed style, designate toolbar button indexes at which the toolbar will wrap. The following code shows how to do this in your main frame window’s OnCreate override:

// Get the style of the first button separator
UINT nStyle = m_wndToolBar->GetButtonStyle( 3 );
// Augment the state for wrapping
nStyle |= TBBS_WRAPPED;
m_wndToolBar->SetButtonStyle( 3, nStyle );

// Do the same for other wrap locations ...

// Set the bar style to size fixed
m_wndToolBar->SetBarStyle(m_wndToolBar->GetBarStyle() |
       CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_FIXED);

// Call docking/floating functions as needed ...

The MFC General sample DOCKTOOL shows how to use member functions of classes CControlBar and CToolBar to manage dynamic layout of a toolbar. See the file EDITBAR.CPP in DOCKTOOL.

What do you want to know more about?

  • Toolbar fundamentals

  • Toolbar tool tips

  • Using your old toolbars


Toolbars: Tool Tips

Home | Overview | How Do I | Sample | Tutorial

Tool tips are the tiny popup windows that present short descriptions of a toolbar button’s purpose when you position the mouse over a button for a period of time. When you create an application with AppWizard that has a toolbar, tool tip support is provided for you. This article explains both the tool tip support created by AppWizard and how to add tool tip support to your application.

This article covers:

  • Activating tool tips

  • Flyby status bar updates

Activating Tool Tips

To activate tool tips in your application, you must do two things:

  • Add the CBRS_TOOLTIPS style to the other styles (such as WS_CHILD, WS_VISIBLE, and other CBRS_ styles) passed as the dwStyle parameter to the CToolBar::Create function or in SetBarStyle.

  • As described in the procedure below, append the toolbar tip text, separated by a newline character (‘\n’), to the string resource containing the command-line prompt for the toolbar command. The string resource shares the ID of the toolbar button.

To add the tool tip text

  1. While you are editing the toolbar in the toolbar editor, open the Toolbar Button Properties window for a given button.

  2. In the Prompt box, specify the text you want to appear in the tool tip for that button.

Note Setting the text as a button property in the toolbar editor replaces the former procedure, in which you had to open and edit the string resource.

If a control bar with tool tips enabled has child controls placed on it, the control bar will display a tool tip for every child control on the control bar as long as it meets the following criteria:

  • The ID of the control is not – 1.

  • The string-table entry with the same ID as the child control in the resource file has a tool tip string.

Flyby Status Bar Updates

A feature related to tool tips is “flyby” status bar updating. By default, the message on the status bar describes only a particular toolbar button when the button is activated. By including CBRS_FLYBY in your list of styles passed to CToolBar::Create, you can have these messages updated when the mouse cursor passes over the toolbar without actually activating the button.

What do you want to know more about?

  • General information about toolbars

  • Docking and floating toolbars

  • Toolbar tool tips

  • The CToolBar and CToolBarCtrl classes

  • Working with the toolbar control

  • Using your old toolbars


Toolbars: Working with the Toolbar Control

Home | Overview | How Do I | Sample | Tutorial

This article explains how you can access the CToolBarCtrl object underlying a CToolBar for greater control over your toolbars. This is an advanced topic.

To access the toolbar common control underlying your CToolBar object

  • Call CToolBar::GetToolBarCtrl.

GetToolBarCtrl returns a reference to a CToolBarCtrl object. You can use the reference to call member functions of the toolbar control class.

Caution While calling CToolBarCtrl Get functions is safe, use caution if you call the Set functions. This is an advanced topic. Normally you shouldn’t need to access the underlying toolbar control.

What do you want to know more about?

  • Using Windows common controls

  • Toolbar fundamentals

  • The MFC toolbar implementation

  • Docking and floating toolbars

  • Dynamically resizing a toolbar

  • Toolbar tool tips

  • Flyby status bar updates

  • Handling tool tip notifications

  • The CToolBar and CToolBarCtrl classes

  • Handling toolbar customization notifications

  • Multiple toolbars

  • Using your old toolbars

  • Control bars

For general information about using Windows common controls, see Common Controls in the Windows 95 SDK Programmer’s Reference.


Toolbars: Using Your Old Toolbars

Home | Overview | How Do I | Sample | Tutorial

If you have used previous versions of Visual C++ to create customized toolbars, the new implementation of class CToolBar could cause you problems. So that you don’t have to give up your old toolbars to use the new functionality, the old implementation is still supported.

The older implementation of class CToolBar is now available in the OLDBARS sample program. For information on how to use that code in your own application, see the sample abstract for OLDBARS.

The DOCKTOOL sample does not use the old-style toolbars, only the new-style toolbars.

You can’t edit old-style toolbars with the toolbar resource editor.

What do you want to know more about?

  • Toolbar fundamentals

  • Docking and floating toolbars

  • Toolbar tool tips

  • Working with the toolbar control


Window Topics

Home | Overview | How Do I | Tutorial

This family of articles covers window objects in the MFC framework. All MFC windows derive from class CWnd, including frame windows, views, dialog boxes, and controls.

The first group of articles describes window objects in general. Refer to this group for general information about C++ window objects, how they encapsulate an HWND, and how you use them when creating your own windows, such as child windows.

The second group of articles describes frame windows—windows that put a frame around content—in particular. Refer to this group for information about how the MFC framework manages frame windows and the contents that they frame, including control bars and views.

What do you want to know more about?

Topics on Window Objects in General

  • Window objects

  • C++ window objects and HWND handles

  • Window classes derived from class CWnd

  • Creating window objects

  • Registering window “classes”

  • Working with window objects

  • Device contexts: objects that make Windows drawing device-independent

  • Graphic objects: pens, brushes, fonts, bitmaps, palettes, regions

Frame Window Topics

  • Frame windows: window objects that provide frames

  • Frame windows and views

  • Frame-window classes

  • Frame-window styles

  • Changing the styles of a window created by MFC

  • What frame windows do

  • Using frame windows

  • The MDICLIENT window

  • Managing menus, control bars, and accelerators


Window Object Topics

Home | Overview | How Do I | Tutorial

A C++ window object (whether for a frame window or some other kind of window) is distinct from its corresponding Windows window (the HWND), but the two are tightly linked. A good understanding of the relationship between a C++ window object and an HWND is crucial for effective programming with MFC.

The general literature on programming for Windows is a good resource for learning how to use the CWnd member functions, which typically encapsulate the HWND APIs. See Books That Help You Learn MFC.

Functions for Operating On a CWnd

CWnd and its derived classes provide constructors, destructors, and member functions to initialize the object, create the underlying Windows structures, and access the encapsulated HWND. CWnd also provides member functions that encapsulate Windows APIs for sending messages, accessing the window’s state, converting coordinates, updating, scrolling, accessing the Clipboard, and many other tasks. Most Windows window-management APIs that take an HWND argument are encapsulated as member functions of CWnd. The names of the functions and their parameters are preserved in the CWnd member function. For details about the Windows APIs encapsulated by CWnd, see class CWnd.

CWnd and Windows Messages

One of the primary purposes of CWnd is to provide an interface for handling Windows messages, such as WM_PAINT or WM_MOUSEMOVE. Many of the member functions of CWnd are handlers for standard messages—those beginning with the identifier afx_msg and the prefix “On,” such as OnPaint and OnMouseMove. Message Handling and Mapping Topics covers messages and message handling in detail. The information there applies equally to the framework’s windows and those that you create yourself for special purposes.

What do you want to know more about?

  • The relationship between a C++ window object and an HWND

  • Working with windows of your own

  • Window classes derived from class CWnd

  • Registering window “classes” (as in Win32 SDK programming)

  • General window creation sequence

  • Destroying window objects

  • Device contexts: objects that make Windows drawing device independent

  • Graphic objects: pens, brushes, fonts, bitmaps, palettes, regions

  • One-stage and two-stage construction of objects such as pens

  • Selecting a graphic object into a device context


Relationship Between a C++ Window Object and an HWND

Home | Overview | How Do I | Tutorial

The window object is an object of the C++ CWnd class (or a derived class) that your program creates directly. It comes and goes in response to your program’s constructor and destructor calls. The Windows window, on the other hand, is an opaque handle to an internal Windows data structure that corresponds to a window and consumes system resources when present. A Windows window is identified by a “window handle” (HWND) and is created after the CWnd object is created by a call to the Create member function of class CWnd. The window may be destroyed either by a program call or by a user’s action. The window handle is stored in the window object’s m_hWnd member variable. The following figure shows the relationship between the C++ window object and the Windows window. Creating windows is discussed in Creating Windows. Destroying windows is discussed in Destroying Window Objects.

Window Object and Windows Window


Derived Window Classes

Home | Overview | How Do I | Tutorial

You can create windows directly from CWnd, or derive new window classes from CWnd. This is how you typically create your own child windows. However, most windows used in a framework program are instead created from one of the CWnd-derived frame-window classes supplied by MFC.

Frame Window Classes

CFrameWnd

Used for SDI frame windows that frame a single document and its view. The frame window is both the main frame window for the application and the frame window for the current document.

CMDIFrameWnd

Used as the main frame window for MDI applications. The main frame window is a container for all MDI document windows and shares its menu bar with them. An MDI frame window is a top-level window that appears on the desktop.

CMDIChildWnd

Used for individual documents opened in an MDI main frame window. Each document and its view are framed by an MDI child frame window contained by the MDI main frame window. An MDI child window looks much like a typical frame window but is contained inside an MDI frame window instead of sitting on the desktop. However, the MDI child window lacks a menu bar of its own and must share the menu bar of the MDI frame window that contains it.

For more information, see Frame Windows.

Other Window Classes Derived from CWnd

In addition to frame windows, several other major categories of windows are derived from CWnd:

Views

Views are created using the CWnd-derived class CView (or one of its derived classes). A view is attached to a document and acts as an intermediary between the document and the user. A view is a child window (not an MDI child) that typically fills the client area of an SDI frame window or an MDI child frame window (or that portion of the client area not covered by a toolbar and/or a status bar).

Dialog Boxes

Dialog boxes are created using the CWnd-derived class CDialog.

Forms

Form views based on dialog-template resources, such as dialog boxes, are created using classes CFormView, CRecordView, or CDaoRecordView.

Controls

Controls such as buttons, list boxes, and combo boxes are created using other classes derived from CWnd. See Controls: Overview.

Control Bars

Child windows that contain controls. Examples include toolbars and status bars. See Control Bars: Overview.

Window Class Hierarchy

Refer to the MFC hierarchy chart in the Class Library Reference. Views are explained in Document/View: Overview. Dialog boxes are explained in Dialog Boxes: Overview.

Creating Your Own Special-Purpose Window Classes

In addition to the window classes provided by the class library, you may need special-purpose child windows. To create such a window, write your own CWnd-derived class and make it a child window of a frame or view. Bear in mind that the framework manages the extent of the client area of a document frame window. Most of the client area is managed by a view, but other windows, such as control bars or your own custom windows, may share the space with the view. You may need to interact with the mechanisms in classes CView and CControlBar for positioning child windows in a frame window’s client area.

Creating Windows discusses creation of window objects and the Windows windows they manage.


Creating Windows

Home | Overview | How Do I | Tutorial

The framework automatically creates most of the windows you need in a framework program. Document/View Creation shows how the framework creates the frame windows associated with documents and views. But for special purposes you can create your own windows—including your own child windows of frame windows or views—in addition to the windows supplied by the framework.

What do you want to know more about?

  • Registering window “classes” (as opposed to C++ window objects)

  • General window creation sequence

  • Destroying window objects

  • Working with window objects


Registering Window "Classes"

Registering Window “Classes”

Home | Overview | How Do I | Tutorial

Window “classes” in traditional programming for Windows define the characteristics of a “class” (not a C++ class) from which any number of windows can be created. This kind of class is a template or model for creating windows.

Window Class Registration in Traditional Programs for Windows

In a traditional program for Windows, without MFC, you process all messages to a window in its “window procedure” or “WndProc.” A WndProc is associated with a window by means of a “window class registration” process. The main window is registered in the WinMain function, but other classes of windows can be registered anywhere in the application. Registration depends on a structure that contains a pointer to the WndProc function together with specifications for the cursor, background brush, and so forth. The structure is passed as a parameter, along with the string name of the class, in a prior call to the RegisterClass function. Thus, a registration class can be shared by multiple windows.

Window Class Registration in MFC Programs

In contrast, most window class registration activity is done automatically in an MFC framework program. If you are using MFC, you typically derive a C++ window class from an existing library class using the normal C++ syntax for class inheritance. The framework still uses traditional “registration classes,” and it provides several standard ones, registered for you in the standard application initialization function. You can register additional registration classes by calling the AfxRegisterWndClass global function and then passing the registered class to the Create member function of CWnd. As described here, the traditional “registration class” in Windows is not to be confused with a C++ class.

For more information, see Technical Note 1.


General Window Creation Sequence

Home | Overview | How Do I | Tutorial

When you create a window of your own, such as a child window, the framework uses much the same process as that described in Document/View Creation.

All the window classes provided by MFC employ two-stage construction. That is, during an invocation of the C++ new operator, the constructor allocates and initializes a C++ object but does not create a corresponding Windows window. That is done afterward by calling the Create member function of the window object.

The Create member function makes the Windows window and stores its HWND in the C++ object’s public data member m_hWnd. Create gives complete flexibility over the creation parameters. Before calling Create, you may want to register a window class with the global function AfxRegisterWndClass in order to set the icon and class styles for the frame.

For frame windows, you can use the LoadFrame member function instead of Create. LoadFrame makes the Windows window using fewer parameters. It gets many default values from resources, including the frame’s caption, icon, accelerator table, and menu.

Note Your icon, accelerator table, and menu resources must have a common resource ID, such as IDR_MAINFRAME.

What do you want to know more about?

  • Window objects

  • Registering window “classes”

  • Destroying window objects

  • Creating document frame windows


Destroying Window Objects

Home | Overview | How Do I | Tutorial

Care must be taken with your own child windows to destroy the C++ window object when the user is finished with the window. If these objects are not destroyed, your application will not recover their memory. Fortunately, the framework manages window destruction as well as creation for frame windows, views, and dialog boxes. If you create additional windows, you are responsible for destroying them.

What do you want to know more about?

  • Window destruction sequence

  • Allocating and deallocating window memory

  • Detaching a CWnd from its HWND

  • Creating window objects

  • Destroying frame windows


Window Destruction Sequence

Home | Overview | How Do I | Tutorial

In the MFC framework, when the user closes the frame window, the window’s default OnClose handler calls DestroyWindow. The last member function called when the Windows window is destroyed is OnNcDestroy, which does some cleanup, calls the Default member function to perform Windows cleanup, and lastly calls the virtual member function PostNcDestroy. The CFrameWnd implementation of PostNcDestroy deletes the C++ window object.

What do you want to know more about?

  • Allocating and deallocating window memory

  • Detaching a CWnd from its HWND


Allocating and Deallocating Window Memory

Home | Overview | How Do I | Tutorial

Do not use the C++ delete operator to destroy a frame window or view. Instead, call the CWnd member function DestroyWindow. Frame windows, therefore, should be allocated on the heap with operator new. Be careful when allocating frame windows on the stack frame or globally. Other windows should be allocated on the stack frame whenever possible.

What do you want to know more about?

  • Creating windows

  • Window destruction sequence

  • Detaching a CWnd from its HWND


Detaching a CWnd from Its HWND

Home | Overview | How Do I | Tutorial

If you need to circumvent the object-HWND relationship, MFC provides another CWnd member function, Detach, which disconnects the C++ window object from the Windows window. This prevents the destructor from destroying the Windows window when the object is destroyed.

What do you want to know more about?

  • Creating windows

  • Window destruction sequence

  • Allocating and deallocating window memory


Working with Window Objects

Home | Overview | How Do I | Tutorial

Working with windows calls for two kinds of activity:

  • Handling Windows messages

  • Drawing in the window

To handle Windows messages in any window, including your own child windows, use ClassWizard to map the messages to your C++ window class. Then write message-handler member functions in your class.

Most drawing in a framework application occurs in the view, whose OnDraw member function is called whenever the window’s contents must be drawn. If your window is a child of the view, you might delegate some of the view’s drawing to your child window by having OnDraw call one of your window’s member functions.

In any case, you will need a device context for drawing. You can use the stock pen, brush, and other graphic objects contained in the device context associated with your window. Or you can modify these objects to get the drawing effects you need. With your device context set up as you like, call member functions of class CDC (device-context class) to draw lines, shapes, and text; to use colors; and to work with a coordinate system.

What do you want to know more about?

  • Message handling

  • Drawing in a view

  • Device contexts

  • Graphic objects


Device Contexts

Home | Overview | How Do I | Tutorial

A device context is a Windows data structure containing information about the drawing attributes of a device such as a display or a printer. All drawing calls are made through a device-context object, which encapsulates the Windows APIs for drawing lines, shapes, and text. Device contexts allow device-independent drawing in Windows. Device contexts can be used to draw to the screen, to the printer, or to a metafile.

CPaintDC objects encapsulate the common idiom of Windows, calling the BeginPaint function, then drawing in the device context, then calling the EndPaint function. The CPaintDC constructor calls BeginPaint for you, and the destructor calls EndPaint. The simplified process is to create the CDC object, draw, and destroy the CDC object. In the framework, much of even this process is automated. In particular, your OnDraw function is passed a CPaintDC already prepared (via OnPrepareDC), and you simply draw into it. It is destroyed by the framework and the underlying device context is released to Windows upon return from the call to your OnDraw function.

CClientDC objects encapsulate working with a device context that represents only the client area of a window. The CClientDC constructor calls the GetDC function, and the destructor calls the ReleaseDC function. CWindowDC objects encapsulate a device context that represents the whole window, including its frame.

CMetaFileDC objects encapsulate drawing into a Windows metafile. In contrast to the CPaintDC passed to OnDraw, you must in this case call OnPrepareDC yourself.

Mouse Drawing

Most drawing in a framework program—and thus most device-context work—is done in the view’s OnDraw member function. However, you can still use device-context objects for other purposes. For example, to provide tracking feedback for mouse movement in a view, you need to draw directly into the view without waiting for OnDraw to be called.

In such a case, you can use a CClientDC device-context object to draw directly into the view.

What do you want to know more about?

  • Device contexts in Win32 documentation

  • Drawing

  • Drawing tutorial

  • Mouse drawing

  • Mouse drawing tutorial

  • Lines and curves

  • Filled shapes

  • Fonts and text

  • Colors

  • Coordinate spaces and transformations


Graphic Objects

Home | Overview | How Do I | Tutorial

Windows provides a variety of drawing tools to use in device contexts. It provides pens to draw lines, brushes to fill interiors, and fonts to draw text. MFC provides graphic-object classes equivalent to the drawing tools in Windows. The table below shows the available classes and the equivalent Windows graphics device interface (GDI) handle types.

The general literature on programming for the Windows GDI applies to the Microsoft Foundation classes that encapsulate GDI graphic objects. This article explains the use of these graphic-object classes:

Classes for Windows GDI Objects

Class | Windows handle type
CPen | HPEN
CBrush | HBRUSH
CFont | HFONT
CBitmap | HBITMAP
CPalette | HPALETTE
CRgn | HRGN

Each graphic-object class in the class library has a constructor that allows you to create graphic objects of that class, which you must then initialize with the appropriate create function, such as CreatePen.

Each graphic-object class in the class library has a cast operator that will cast an MFC object to the associated Windows handle. The resulting handle is valid until the associated object detaches it. Use the object’s Detach member function to detach the handle.

The following code casts a CPen object to a Windows handle:

CPen myPen;
myPen.CreateSolidPen( PS_COSMETIC, 1, RGB(255,255,0) );
HPEN hMyPen = (HPEN) myPen;

Process of Creating a Graphic Object in a Device Context

The following four steps are typically used when you need a graphic object for a drawing operation:

  1. Define a graphic object on the stack frame. Initialize the object with the type-specific create function, such as CreatePen. Alternatively, initialize the object in the constructor. See the discussion of one-stage and two-stage creation, which provides example code.

  2. Select the object into the current device context, saving the old graphic object that was selected before.

  3. When done with the current graphic object, select the old graphic object back into the device context to restore its state.

  4. Allow the frame-allocated graphic object to be deleted automatically when the scope is exited.

Note If you will be using a graphic object repeatedly, you can allocate it once and select it into a device context each time it is needed. Be sure to delete such an object when you no longer need it.

What do you want to know more about?

  • One-stage and two-stage construction of graphic objects

  • Example of constructing a pen in one and two stages

  • Example of selecting a pen into a device context

  • Device contexts


One-Stage and Two-Stage Construction of Objects

Home | Overview | How Do I | Tutorial

You have a choice between two techniques for creating graphic objects, such as pens and brushes:

  • One-stage construction: Construct and initialize the object in one stage, all with the constructor.

  • Two-stage construction: Construct and initialize the object in two separate stages. The constructor creates the object and an initialization function initializes it.

Two-stage construction is always safer. In one-stage construction, the constructor could throw an exception if you provide incorrect arguments or memory allocation fails. That problem is avoided by two-stage construction, although you do have to check for failure. In either case, destroying the object is the same process.

Note These techniques apply to creating any objects, not just graphic objects.

Example of Both Construction Techniques

The following brief example shows both methods of constructing a pen object:

void CMyView::OnDraw( CDC* pDC )
{
// One-stage
    CPen myPen1( PS_DOT, 5, RGB(0,0,0) );

// Two-stage: first construct the pen
    CPen myPen2;
    // Then initialize it
    if( myPen2.CreatePen( PS_DOT, 5, RGB(0,0,0) ) )
        // Use the pen
}

What do you want to know more about?

  • Graphic objects

  • Selecting a graphic object into a device context

  • Device contexts

  • Drawing


Selecting a Graphic Object into a Device Context

Home | Overview | How Do I | Tutorial

This topic applies to using graphic objects in a window’s device context. After you create a drawing object, you must select it into the device context in place of the default object stored there:

void CMyView::OnDraw( CDC* pDC )
{
    CPen penBlack;  // Construct it, then initialize
    if( newPen.CreatePen( PS_SOLID, 2, RGB(0,0,0) ) )
    {
        // Select it into the device context
        // Save the old pen at the same time
        CPen* pOldPen = pDC->SelectObject( &penBlack );

        // Draw with the pen
        pDC->MoveTo(...);
        pDC->LineTo(...);

        // Restore the old pen to the device context
        pDC->SelectObject( pOldPen );
    }
    else
    {
        // Alert the user that resources are low
    }
}

Lifetime of Graphic Objects

The graphic object returned by SelectObject is “temporary.” That is, it will be deleted by the OnIdle member function of class CWinApp the next time the program gets idle time. As long as you use the object returned by SelectObject in a single function without returning control to the main message loop, you will have no problem.

What do you want to know more about?

  • Graphic objects

  • One-stage and two-stage construction of graphic objects

  • Device contexts

  • Drawing


Frame Window Topics

Home | Overview | How Do I | Tutorial

When an application runs under Microsoft Windows, the user interacts with documents displayed in frame windows. A document frame window has two major components: the frame and the contents that it frames. A document frame window can be a single document interface (SDI) frame window or a multiple document interface (MDI) child window. Windows manages most of the user’s interaction with the frame window: moving and resizing the window, closing it, and minimizing and maximizing it. You manage the contents inside the frame.

Frame Windows and Views

The MFC framework uses frame windows to contain views. The two components—frame and contents—are represented and managed by two different classes in MFC. A frame-window class manages the frame, and a view class manages the contents. The view window is a child of the frame window. Drawing and other user interaction with the document take place in the view’s client area, not the frame window’s client area. The frame window provides a visible frame around a view, complete with a caption bar and standard window controls such as a control menu, buttons to minimize and maximize the window, and controls for resizing the window. The “contents” consist of the window’s client area, which is fully occupied by a child window—the view. The following figure shows the relationship between a frame window and a view.

Frame Window and View

Frame Windows and Splitter Windows

Another common arrangement is for the frame window to frame multiple views, usually using a splitter window. In a splitter window, the frame window’s client area is occupied by a splitter window, which in turn has multiple child windows, called panes, which are views.

What do you want to know more about?

General Frame Window Topics

  • Window objects in C++

  • MFC window classes

  • Window classes that AppWizard creates

  • Frame window styles

  • What frame windows do

Topics on Using Frame Windows

  • Using frame windows

  • Creating frame windows for documents

  • Destroying frame windows

  • Managing MDI child windows

  • Managing the current view in a frame window that contains more than one view

  • Managing other objects that share the frame window’s space: menus, control bars, and accelerators

Topics on Special Frame Window Capabilities

  • Dragging and dropping files from Windows Explorer or File Manager into a frame window

  • Responding to dynamic data exchange (DDE)

  • Frame windows and semimodal states: context-sensitive Windows Help

  • Frame windows and semimodal states: printing and print preview

Topics on Other Kinds of Windows

  • Views

  • Dialog boxes

  • Controls


Frame-Window Classes

Home | Overview | How Do I | Tutorial

Each application has one “main frame window,” a desktop window that usually has the application name in its caption. Each document usually has one “document frame window.” A document frame window contains at least one view, which presents the document’s data.

Frame Windows in SDI and MDI Applications

For an SDI application, there is one frame window derived from class CFrameWnd. This window is both the main frame window and the document frame window. For an MDI application, the main frame window is derived from class CMDIFrameWnd, and the document frame windows, which are MDI child windows, are derived from class CMDIChildWnd.

Use the Frame-Window Class, or Derive from It?

These classes provide most of the frame-window functionality you need for your applications. Under normal circumstances, the default behavior and appearance they provide will suit your needs. If you need additional functionality, derive from these classes.

What do you want to know more about?

  • Frame-window classes created by AppWizard

  • Frame-window styles

  • Changing the styles of a window created by MFC


The Frame-Window Classes Created by AppWizard

Home | Overview | How Do I | Tutorial

When you use AppWizard to create a skeleton application, in addition to application, document, and view classes, AppWizard creates a derived frame-window class for your application’s main frame window. The class is called CMainFrame by default, and the files that contain it are named MAINFRM.H and MAINFRM.CPP.

If your application is SDI, your CMainFrame class is derived from class CFrameWnd. If your application is MDI, CMainFrame is derived from class CMDIFrameWnd. If you choose to support a toolbar, the class also has member variables of type CToolBar and CStatusBar and an OnCreate message-handler function to initialize the two control bars.

If your application is MDI, AppWizard does not derive a new document frame-window class for you. Instead, it uses the default implementation in CMDIChildWnd. Later on, if you need to customize your document frame window, you can use ClassWizard to create a new document frame-window class.

These frame-window classes work as created, but to enhance their functionality, you must add member variables and member functions. You may also want to have your window classes handle other Windows messages.


Frame-Window Styles

Home | Overview | How Do I | Tutorial

The frame windows you get with the framework are suitable for most programs, but you can gain additional flexibility by using the advanced functions PreCreateWindow and the MFC global function AfxRegisterWndClass. PreCreateWindow is a member function of CWnd.

If you apply the WS_HSCROLL and WS_VSCROLL styles to the main frame window, they are instead applied to the MDICLIENT window so users can scroll the MDICLIENT area.

If the window’s FWS_ADDTOTITLE style bit is set (which it is by default), the view tells the frame window what title to display in the window’s title bar based on the view’s document name.

What do you want to know more about?

  • MDICLIENT, the window within an MDI frame that contains the MDI child windows

  • Changing the styles of a window created by MFC

  • Available styles


Changing the Styles of a Window Created by MFC

Home | Overview | How Do I | Tutorial

In its version of the WinMain function, MFC registers several standard window classes for you. Because you don’t normally edit MFC’s WinMain, that function gives you no opportunity to change the MFC default window styles. This article explains how you can change the styles of such a preregistered window class in an existing application.

Changing Styles in a New MFC Application

If you’re using Visual C++ 2.0 or later, you can change the default window styles in AppWizard when you create your application. In AppWizard’s Advanced Options dialog box, choose the Main Frame tab (to change styles for your main frame window) or the MDI Child Frame tab (to change styles for MDI child windows). For either window type, you can specify its frame thickness (thick or thin) and any of the following:

  • Whether the window has Minimize or Maximize controls.

  • Whether the window appears initially minimized, maximized, or neither.

For main frame windows, you can also specify whether the window has a System Menu. For MDI child windows, you can specify whether the window supports splitter panes.

Changing Styles in an Existing Application

If you’re using a version of Visual C++ prior to version 2.0 or changing window attributes in an existing application, follow the instructions in the rest of this article instead.

To change the default window attributes used by a framework application created with AppWizard, override the window’s PreCreateWindow virtual member function. PreCreateWindow allows an application to access the creation process normally managed internally by the CDocTemplate class. The framework calls PreCreateWindow just prior to creating the window. By modifying the CREATESTRUCT parameter to PreCreateWindow, your application can change the attributes used to create the window.

The CTRLBARS sample application demonstrates this technique for changing window attributes. Depending on what your application changes in PreCreateWindow, it may be necessary to call the base class implementation of the function.

The following discussion covers the SDI case and the MDI case.

The SDI Case

In a single document interface (SDI) application, the default window style in the framework is a combination of the WS_OVERLAPPEDWINDOW and FWS_ADDTOTITLE styles. FWS_ADDTOTITLE is an MFC-specific style that instructs the framework to add the document title to the window’s caption. To change the window attributes in an SDI application, override the PreCreateWindow function in your class derived from CFrameWnd (which AppWizard names CMainFrame). For example:

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
    // Create a window without min/max buttons or sizable border
    cs.style = WS_OVERLAPPED | WS_SYSMENU | WS_BORDER;

    // Size the window to 1/3 screen size and center it
    cs.cy = ::GetSystemMetrics(SM_CYSCREEN) / 3;
    cs.cx = ::GetSystemMetrics(SM_CXSCREEN) / 3;
    cs.y = ((cs.cy * 3) - cs.cy) / 2;
    cs.x = ((cs.cx * 3) - cs.cx) / 2;

    // Call the base-class version
    return CFrameWnd::PreCreateWindow(cs);
}

This code creates a main frame window without Minimize and Maximize buttons and without a sizable border. The window is initially centered on the screen.

The MDI Case

A little more work is required to change the window style of a child window in a multiple document interface (MDI) application. By default, an MDI application created with AppWizard uses the default CMDIChildWnd class defined in MFC. To change the window style of an MDI child window, you must derive a new class from CMDIChildWnd and replace all references to CMDIChildWnd in your project with references to the new class. Most likely, the only reference to CMDIChildWnd in the application is located in your application's InitInstance member function.

The default window style used in an MDI application is a combination of the WS_CHILD, WS_OVERLAPPEDWINDOW, and FWS_ADDTOTITLE styles. To change the window attributes of an MDI application’s child windows, override the PreCreateWindow function in your class derived from CMDIChildWnd. For example:

BOOL CMyChildWnd::PreCreateWindow(CREATESTRUCT& cs)
{
    // Create a child window without the maximize button
    cs.style &= ~WS_MAXIMIZEBOX;

    // Call the base-class version
    return CMDIChildWnd::PreCreateWindow(cs);
}

This code creates MDI child windows without a Maximize button.

What do you want to know more about?

  • Available styles

  • Frame-window styles

  • General window styles


What Frame Windows Do

Home | Overview | How Do I | Tutorial

Besides simply framing a view, frame windows are responsible for numerous tasks involved in coordinating the frame with its view and with the application. CMDIFrameWnd and CMDIChildWnd inherit from CFrameWnd, so they have CFrameWnd capabilities as well as new capabilities that they add. Examples of child windows include views, controls such as buttons and list boxes, and control bars, including toolbars, status bars, and dialog bars.

The frame window is responsible for managing the layout of its child windows. In the MFC framework, a frame window positions any control bars, views, and other child windows inside its client area.

The frame window also forwards commands to its views and can respond to notification messages from control windows.

What do you want to know more about?

  • How views and control bars fit into the frame window

  • How menus and accelerators fit into the frame window

  • How commands are routed from the frame window to its view and other command targets

  • Views

  • Control bars

  • Controls


Using Frame Windows

Home | Overview | How Do I | Tutorial

The MFC framework creates document frame windows—and their views and documents—as part of its implementation of the New and Open commands on the File menu. Because the framework does most of the frame-window work for you, you play only a small role in creating, using, and destroying those windows. You can, however, explicitly create your own frame windows and child windows for special purposes.

What do you want to know more about?

  • Creating document frame windows

  • Destroying frame windows

  • Managing MDI child windows

  • Managing the current view

  • Managing menus, control bars, and accelerators

  • Dragging and dropping files in a frame window

  • Responding to dynamic data exchange (DDE)

  • Orchestrating other window actions

  • Managing context-sensitive help

  • The frame window’s role in printing and print preview


Creating Document Frame Windows

Home | Overview | How Do I | Tutorial

Document/View Creation shows how the CDocTemplate object orchestrates creating the frame window, document, and view and connecting them all together. Three CRuntimeClass arguments to the CDocTemplate constructor specify the frame window, document, and view classes that the document template creates dynamically in response to user commands such as the New command on the File menu or the New Window command on an MDI Window menu. The document template stores this information for later use when it creates a frame window for a view and document.

For the RUNTIME_CLASS mechanism to work correctly, your derived frame-window classes must be declared with the DECLARE_DYNCREATE macro. This is because the framework needs to create document frame windows using the dynamic construction mechanism of class CObject.

When the user chooses a command that creates a document, the framework calls upon the document template to create the document object, its view, and the frame window that will display the view. When it creates the document frame window, the document template creates an object of the appropriate class—a class derived from CFrameWnd for an SDI application or from CMDIChildWnd for an MDI application. The framework then calls the frame-window object’s LoadFrame member function to get creation information from resources and to create the Windows window. The framework attaches the window handle to the frame-window object. Then it creates the view as a child window of the document frame window.

Use caution in deciding when to initialize your CWnd-derived object.

What do you want to know more about?

  • Class CObject and its dynamic creation mechanism

  • Document templates and frame window creation

  • Destroying frame windows


When to Initialize CWnd Objects

Home | Overview | How Do I | Tutorial

You cannot create your own child windows or call any Windows API functions in the constructor of a CWnd-derived object. This is because the HWND for the CWnd object has not been created yet. Most Windows-specific initialization, such as adding child windows, must be done in an OnCreate message handler.

What do you want to know more about?

  • Creating document frame windows

  • Document/view creation


Destroying Frame Windows

Home | Overview | How Do I | Tutorial

The MFC framework manages window destruction as well as creation for those windows associated with framework documents and views. If you create additional windows, you are responsible for destroying them.

In the framework, when the user closes the frame window, the window’s default OnClose handler calls DestroyWindow. The last member function called when the Windows window is destroyed is OnNcDestroy, which does some cleanup, calls the Default member function to perform Windows cleanup, and lastly calls the virtual member function PostNcDestroy. The CFrameWnd implementation of PostNcDestroy deletes the C++ window object. You should never use the C++ delete operator on a frame window. Use DestroyWindow instead.

When the main window closes, the application closes. If there are modified unsaved documents, the framework displays a message box to ask if the documents should be saved and ensures that the appropriate documents are saved if necessary.

What do you want to know more about?

  • Creating document frame windows


Managing MDI Child Windows

Home | Overview | How Do I | Tutorial

MDI main frame windows (one per application) contain a special child window called the MDICLIENT window. The MDICLIENT window manages the client area of the main frame window, and itself has child windows: the document windows, derived from CMDIChildWnd. Because the document windows are frame windows themselves (MDI child windows), they can also have their own children. In all of these cases, the parent window manages its child windows and forwards some commands to them.

In an MDI frame window, the frame window manages the MDICLIENT window, repositioning it in conjunction with control bars. The MDICLIENT window, in turn, manages all MDI child frame windows. The following figure shows the relationship between an MDI frame window, its MDICLIENT window, and its child document frame windows.

MDI Frame Windows and Children

An MDI frame window also works in conjunction with the current MDI child window, if there is one. The MDI frame window delegates command messages to the MDI child before it tries to handle them itself.

What do you want to know more about?

  • Creating frame windows

  • Frame-window styles


Managing the Current View

Home | Overview | How Do I | Tutorial

As part of the default implementation of frame windows, a frame window keeps track of a currently active view. If the frame window contains more than one view, as for example in a splitter window, the current view is the most recent view in use. The active view is independent of the active window in Windows or the current input focus.

When the active view changes, the framework notifies the current view by calling its OnActivateView member function. You can tell whether the view is being activated or deactivated by examining OnActivateView’s bActivate parameter. By default, OnActivateView sets the focus to the current view on activation. You can override OnActivateView to perform any special processing when the view is deactivated or reactivated. For example, you might want to provide special visual cues to distinguish the active view from other, inactive views.

A frame window forwards commands to its current (active) view, as described in Command Routing, as part of the standard command routing.


Managing Menus, Control Bars, and Accelerators

Home | Overview | How Do I | Tutorial

The frame window manages updating user-interface objects, including menus, toolbar buttons, the status bar, and accelerators. It also manages sharing the menu bar in MDI applications.

Managing Menus

The frame window participates in updating user-interface items using the ON_UPDATE_COMMAND_UI mechanism described in How to Update User-Interface Objects. Buttons on toolbars and other control bars are updated during the idle loop. Menu items in drop-down menus on the menu bar are updated just before the menu drops down.

For MDI applications, the MDI frame window manages the menu bar and caption. An MDI frame window owns one default menu that is used as the menu bar when there are no active MDI child windows. When there are active children, the MDI frame window’s menu bar is taken over by the menu for the active MDI child window. If an MDI application supports multiple document types, such as chart and worksheet documents, each type puts its own menus into the menu bar and changes the main frame window’s caption.

CMDIFrameWnd provides default implementations for the standard commands on the Window menu that appears for MDI applications. In particular, the New Window command (ID_WINDOW_NEW) is implemented to create a new frame window and view on the current document. You need to override these implementations only if you need advanced customization.

Multiple MDI child windows of the same document type share menu resources. If several MDI child windows are created by the same document template, they can all use the same menu resource, saving on system resources in Windows.

Managing the Status Bar

The frame window also positions the status bar within its client area and manages the status bar’s indicators. The frame window clears and updates the message area in the status bar as needed and displays prompt strings as the user selects menu items or toolbar buttons, as described in How to Display Command Information in the Status Bar.

Managing Accelerators

Each frame window maintains an optional accelerator table that does keyboard accelerator translation for you automatically. This mechanism makes it easy to define accelerator keys (also called shortcut keys) that invoke menu commands.


Dragging and Dropping Files in a Frame Window

Home | Overview | How Do I | Tutorial

The frame window manages a relationship with the Windows Explorer or File Manager.

By adding a few initializing calls in your override of the CWinApp member function InitInstance, as described in CWinApp: The Application Class, you can have your frame window indirectly open files dragged from the Windows Explorer or File Manager and dropped in the frame window. See File Manager Drag and Drop.


Responding to Dynamic Data Exchange (DDE)

Home | Overview | How Do I | Tutorial

The frame window can respond to dynamic data exchange (DDE) requests to open files from the File Manager (if the file extension is registered or associated with the application). See Shell Registration.


Orchestrating Other Window Actions

Home | Overview | How Do I | Tutorial

The frame window orchestrates semimodal states such as context-sensitive help and print preview. The framework’s role in managing context-sensitive help is described in the article Help: Context-Sensitive Help Overview. For a description of the frame window’s role in print preview, see Printing and Print Preview: Overview.


Adding Program Functionality

Most of programming is the iterative process of adding one program subsystem after another. Perhaps you begin with your program's "engine," such as the calculation engine for a spreadsheet application or the formatting engine for a word processor. Then you might develop your program's OLE functionality, and so on. This book covers a wide range of topics useful in this phase of development.
Overviews Short introductions to the concepts important in adding core functionality to your program
How Do I Explanations of the tasks to perform as you add program functionality
Frequently Asked Questions Focused questions that other Visual C++ users are asking too
Details Longer conceptual articles about the subjects you need at this stage
What else do you want to do?
Learn how to use ClassView.
Learn how to use WizardBar.
Learn how to use ClassWizard.
Learn how to use Gallery to reuse code and to insert prepackaged components and ActiveX Controls into your project.
Learn how to use the source code editor effectively.

Interesting home pages
Visual C++ Home The entire Visual C++ product -- and your gateway to all of the documentation
Adding user-interface features Creating your program's user interface -- dialog boxes, toolbars, and much more
Compiling and Linking Building your program so you can test it
Debugging Debugging your program


Overviews: Adding Program Functionality

Home | How Do I | FAQ | Details

Program functionality comes in many forms. Consult the list of overviews below to find brief overview information about an area.

What do you want to know more about?

  • Active Technology: Overview

  • Automation: Overview (including Remote Automation)

  • Assembler (Inline): Overview

  • Calling Conventions: Overview

  • ClassView: Overview

  • WizardBar: Overview

  • ClassWizard: Overview

  • CObject, The Root Base Class in MFC: Overview

  • Collections, Working with Aggregate Data: Overview

  • Compiler COM Support: Overview

  • Databases: Overview

  • Date and Time Data: Overview

  • DLLs: Overview

  • Exception Handling: Overview

  • File Handling: Overview

  • Internet Support: Overview

  • MAPI, Enabling Your Program for Mail: Overview

  • Memory Management: Overview

  • Messages and Commands: Overview

  • MFC: Overview

  • Multibyte Character Sets (MBCS): Overview

  • Multithreaded Programs: Overview

  • OLE in MFC: Overview

  • Reusing Code (using the Gallery): Overview

  • Serialization: Overview

  • Strings: Overview

  • Templates in C++: Overview

  • Unicode Programming: Overview

  • Win32 Programming: Overview

  • Windows Sockets for Network Programming: Overview

  • Working with Classes: Overview


Program Functionality Vs. User-Interface Features: Overview

Home

Why distinguish between "program functionality" and "user-interface features"? Research suggests that most developers prefer to separate the following programming tasks:

  • Designing and connecting a program's user-interface: its menus, toolbars, dialog boxes, windows, and other visible features with which users interact directly

  • Writing the less visible code that implements the program's "engine": the functionality that accomplishes what the program is all about, such as performing spreadsheet calculations or formatting word-processor text

To locate topics related to programming user-interface features, use the Adding User-Interface Features home page.

To locate topics related to implementing deeper program functionality, use the Adding Program Functionality home page.


Active Technology: Overview

Home | How Do I | Details

Active technologies use the Component Object Model (COM) to enable software components to interact with one another in a networked environment, regardless of the language in which they were created. Active technologies can be used to create applications to run on the desktop or the Internet.

What do you want to know more about?

  • Active Technology

  • Active Technology on the Internet

  • Answers to frequently asked questions about Internet programming

  • ActiveX Controls

  • Active Document Servers

  • Active Document Containers

  • Active Documents

  • Automation

  • Remote Automation


Assembler (Inline): Overview

Home | How Do I | Details

Assembly language serves many purposes, such as improving program speed, reducing memory needs, and controlling hardware. You can use the inline assembler to embed assembly-language instructions directly in your C and C++ source programs without extra assembly and link steps. The inline assembler is built into the compiler — you don't need a separate assembler such as the Microsoft Macro Assembler (MASM).

Note Programs with inline assembler code are not fully portable to other hardware platforms. If you are designing for portability, avoid using inline assembler.

What do you want to know more about?

  • Inline assembler

  • The __asm keyword

  • C or C++ in __asm blocks

  • Registers

  • Jumps to labels

  • C function calls from an __asm block

  • C++ function calls from an __asm block

  • __asm blocks as C macros

  • Optimizing inline assembly code


Automation: Overview

Home | How Do I | Details | Sample | Tutorial

Automation (formerly known as OLE Automation) makes it possible for one application to manipulate objects implemented in another application, or to "expose" objects so they can be manipulated.

You can automate any object that exposes an automation interface, providing methods and properties that you can access from other applications. The automated object might be local or remote (on another machine accessible across a network). For remote automation, see Remote Automation. Automation is available for both OLE and COM objects.

Many commercial applications, such as Microsoft Excel and Microsoft Visual C++, allow you to automate much of their functionality. For example, in Visual C++, you can write VBScript macros or Visual C++ add-ins to automate builds, aspects of code editing, or debugging tasks.

What do you want to know more about?

  • Automation

  • Remote Automation


Calling Conventions: Overview

Home | How Do I | Details

The Visual C/C++ compiler provides several ways to call internal and external functions. Understanding these different approaches can help you debug your program and link your code with assembly-language routines.

The Details articles on this subject explain the differences between the calling conventions, how arguments are passed, and how values are returned by functions. They also discuss naked function calls, an advanced feature that enables you to write your own prolog and epilog code.

What do you want to know more about?

  • Calling conventions

  • __cdecl

  • __stdcall

  • __fastcall

  • thiscall

  • Obsolete calling conventions

  • Examples of calling convention use

  • Naked function calls

  • The floating point coprocessor.


CObject, The Root Base Class in MFC: Overview

Home | How Do I | FAQ | Details

Class CObject is the root base class in the MFC class hierarchy. This class provides a number of services, with minimal overhead, to any class derived from it. You can:

  • Dump the object's data for diagnostic purposes

  • Validate the object's internal state

  • Obtain information about the class at run time

  • Have the class serialize itself to persistent storage

  • Make the class dynamically creatable

What do you want to know more about?

  • CObject

  • The major areas of MFC functionality that CObject provides

  • Deriving a new class from CObject

See Also CRuntimeClass


Collections, Working with Aggregate Data: Overview

Home | How Do I | Details | Sample | Tutorial

MFC supplies "collections" (also called aggregate objects) — objects that can store multiple pieces of data of various types, including other objects derived from class CObject.

You can use array, list, or map collections based on C++ templates, or you can use MFC's older predefined array, list, and map objects not based on templates. Using template-based collection classes is recommended for better type safety.

What do you want to know more about?

  • What kinds of collection objects are available

  • Choosing a collection class appropriate to my needs

  • Adding data to a collection

  • Deleting data from a collection

  • Accessing all data in a collection — iterating the collection

  • Deleting all data in a collection

  • Stack collections

  • Queue collections


Compiler COM Support: Overview

Home

The Visual C++ compiler can directly read component object model (COM) type libraries and translate the contents into C++ source code that can be included in the compilation. Language extensions are available to facilitate COM programming on the client side.

By using the #import preprocessor directive, the compiler can read a type library and convert it into a C++ header file that describes the COM interfaces as classes. A set of #import attributes are available for user control of the content for the resulting type library header files.

You can use the __declspec extended attribute uuid to assign a globally unique identifier (GUID) to a COM object. The keyword __uuidof can be used to extract the GUID associated with a COM object. Another __declspec attribute, property, can be used to specify the get and put methods for a data member of a COM object.

What do you want to know more about?

  • The #import preprocessor directive

  • __declspec extended attributes: uuid and property

  • __uuidof

A set of COM support classes are provided to support the VARIANT and BSTR types, implement smart pointers, and encapsulate the error object thrown by _com_raise_error. They are:

  • _com_error

  • _com_ptr_t

  • _variant_t

  • _bstr_t

See Also Compiling and Linking


Databases: Overview

Home | How Do I | FAQ | Details | ODBC Driver List

Visual C++ provides several ways to work with databases. You can directly call database API functions from the DAO or ODBC Software Development Kits (SDKs). Or you can choose to use the Microsoft Foundation Class Library (MFC), and let the MFC DAO classes and MFC ODBC classes simplify working with either database API.

For information on programming directly with the DAO or ODBC API functions, see the DAO SDK or ODBC SDK.

In general, use the MFC DAO classes when you want to work with Microsoft Jet (.MDB) databases. (You can also use DAO to work with external databases, such as ODBC data sources.) Use the MFC ODBC classes when you are not using Jet and want to work with the ODBC API for complete data-source independence. For more detailed information, see the article Database Topics (General).

Tip Besides writing stand-alone database applications, you can often use a database effectively in other kinds of programs as a convenient storage and retrieval medium.

What do you want to know more about?

  • Data Access Objects (DAO)

  • Open Database Connectivity (ODBC)

  • Which kind of database support to use

  • Writing a program that uses DAO

  • Writing a program that uses ODBC

  • Writing a program that uses data-bound controls

Tip Visual C++ includes the Microsoft Knowledge Base. Use this resource to find additional articles on database topics written by product support engineers.


Date and Time Data: Overview

Home | How Do I | Details

Visual C++ supplies several ways to work with date and time data:

  • Run-time library functions for time management

  • Win32 API functions for time management

  • MFC classes CTime, COleDateTime, CTimeSpan, and COleDateTimeSpan

What do you want to know more about?

  • MFC's date and time classes

  • Getting the current time

  • Calculating elapsed time

  • The SYSTEMTIME data type

  • Date and time data in Automation


DLLs: Overview

Home | How Do I | FAQ | Details | Sample

A dynamic-link library (DLL) is an executable file that acts as a shared library of functions. Dynamic linking provides a way for a process to call a function that is not part of its executable code. The executable code for the function is located in a DLL, which contains one or more functions that are compiled, linked, and stored separately from the processes that use them. DLLs also facilitate the sharing of data and resources. Multiple applications can simultaneously access the contents of a single copy of a DLL in memory.

Dynamic linking differs from static linking in that it allows an executable module (either a .DLL or .EXE file) to include only the information needed at run time to locate the executable code for a DLL function. In static linking, the linker gets all the referenced functions from the static link library and places it with your code into your executable. Using DLLs instead of static link libraries makes the size of the executable file smaller. If several applications use the same DLL, this can be a big savings in disk space and memory.

What do you want to do?

  • Export from a DLL

  • Link an executable to a DLL

  • Initialize a DLL

What do you want to know more about?

  • The advantages of using DLLs

  • The different kinds of DLLs available with Visual C++

  • Non-MFC DLLs: Overview

  • Regular DLLs statically linked to MFC: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Extension DLLs: Overview

  • Which kind of DLL to use


The Differences Between Applications and DLLs

Home | Overview | How Do I | FAQ | Details | Sample

Even though DLLs and applications are both executable program modules, they differ in several ways. To the end-user, the most obvious difference is that DLLs are not programs that can be directly executed. From the system's point of view, there are two fundamental differences between applications and DLLs:

  • An application can have multiple instances of itself running in the system simultaneously, whereas a DLL can have only one instance.

  • An application can own things such as a stack, global memory, file handles, and a message queue, but a DLL cannot.

What do you want to do?

  • Export from a DLL

  • Link an executable to a DLL

  • Initialize a DLL

What do you want to know more about?

  • The advantages of using DLLs

  • The different kinds of DLLs available with Visual C++

  • Non-MFC DLLs: Overview

  • Regular DLLs statically linked to MFC: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Extension DLLs: Overview

  • Which kind of DLL to use


The Advantages of Using DLLs

Home | Overview | How Do I | FAQ | Details | Sample

Dynamic linking has the following advantages:

  • Saves memory and reduces swapping. Many processes can use a single DLL simultaneously, sharing a single copy of the DLL in memory. In contrast, Windows must load a copy of the library code into memory for each application that is built with a static link library.

  • Saves disk space. Many applications can share a single copy of the DLL on disk. In contrast, each application built with a static link library has the library code linked into its executable image as a separate copy.

  • Upgrades to the DLL are easier. When the functions in a DLL change, the applications that use them do not need to be recompiled or relinked as long as the functions' arguments and return values do not change. In contrast, statically linked object code requires that the application be relinked when the functions change.

  • Provides after-market support. For example, a display driver DLL can be modified to support a display that was not available when the application was shipped.

  • Supports multi-language programs. Programs written in different programming languages can call the same DLL function as long as the programs follow the function's calling convention The programs and the DLL function must be compatible in the following ways: the order in which the function expects its arguments to be pushed onto the stack, whether the function or the application is responsible for cleaning up the stack, and whether any arguments are passed in registers.

  • Provides a mechanism to extend the MFC library classes. You can derive classes from the existing MFC classes and place them in an MFC extension DLL for use by MFC applications.

  • Eases the creation of international versions. By placing resources in a DLL, it is much easier to create international versions of an application. You can place the strings for each language version of your application in a separate resource DLL, and have the different language versions load the appropriate resources.

A potential disadvantage to using DLLs is that the application is not self-contained; it depends on the existence of a separate DLL module.

What do you want to do?

  • Export from a DLL

  • Link an executable to a DLL

  • Initialize a DLL

What do you want to know more about?

  • The different kinds of DLLs available with Visual C++

  • Non-MFC DLLs: Overview

  • Regular DLLs statically linked to MFC: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Extension DLLs: Overview

  • Which kind of DLL to use


The Different Kinds of DLLs Available with Visual C++

Home | Overview | How Do I | FAQ | Details | Sample

Using Visual C++, you can build Win32 DLLs in C or C++ that do not use the Microsoft Foundation Class Library (MFC). A non-MFC DLL project is created by clicking New on the File menu and then choosing Dynamic-Link Library as your target type on the Projects tab.

The MFC library itself is available in either static link libraries or in a number of DLLs. An MFC DLL project is created by choosing New on the File menu and then choosing MFC AppWizard (DLL) as your target type on the Projects tab. If your DLL is using MFC, Visual C++ supports three different DLL development scenarios:

  • Building a regular DLL that statically links MFC.

  • Building a regular DLL that dynamically links MFC.

  • Building an MFC extension DLL. These always dynamically link MFC.

What do you want to know more about?

  • Non-MFC DLLs: Overview

  • Regular DLLs statically linked to MFC: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Extension DLLs: Overview

  • Which kind of DLL to use


Non-MFC DLLs: Overview

Home | Overview | How Do I | FAQ | Details | Sample

A non-MFC DLL is a DLL that does not use MFC internally, and the exported functions in the DLL can be called by either MFC or non-MFC executable files. Functions are usually exported from a non-MFC DLL using the standard C interface.

For more information about non-MFC DLLs, see Dynamic-Link Libraries in the Win32 SDK documentation.

What do you want to do?

  • Create a Win32 DLL

  • Export from a DLL

  • Link an executable to a DLL

  • Initialize a DLL

What do you want to know more about?

  • Regular DLLs statically linked to MFC: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Extension DLLs: Overview

  • Which kind of DLL to use


Regular DLLs Statically Linked to MFC: Overview

Home | Overview | How Do I | FAQ | Details | Sample

A regular DLL statically linked to MFC is a DLL that uses MFC internally, and the exported functions in the DLL can be called by either MFC or non-MFC executables. As the name describes, this kind of DLL is built using the static link library version of MFC. Functions are usually exported from a regular DLL using the standard C interface. For an example of how to write, build, and use a regular DLL, see the sample DLLTRACE.

Note that the term USRDLL is no longer used in the Visual C++ documentation. A regular DLL that is statically linked to MFC has the same characteristics as the former USRDLL.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

What do you want to do?

  • Initialize a regular DLL

What do you want to know more about?

  • Regular DLLs statically linked to MFC

  • Non-MFC DLLs: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Extension DLLs: Overview

  • Which kind of DLL to use

  • The build settings generated by AppWizard for MFC DLLs


Regular DLLs Dynamically Linked to MFC: Overview

Home | Overview | How Do I | FAQ | Details | Sample

A regular DLL dynamically linked to MFC is a DLL that uses MFC internally, and the exported functions in the DLL can be called by either MFC or non-MFC executables. As the name describes, this kind of DLL is built using the dynamic-link library version of MFC (also known as the shared version of MFC). Functions are usually exported from a regular DLL using the standard C interface. For an example of how to write, build, and use a regular DLL, see the sample DLLTRACE. For more information about regular DLLs that dynamically link to MFC, see the section titled “Converting DLLTRACE to Dynamically Link with the MFC DLL” in the abstract for the sample.

You must add the AFX_MANAGE_STATE macro at the beginning of all the exported functions in regular DLLs that dynamically link to MFC to set the current module state to the one for the DLL. This is done by adding the following line of code to the beginning of functions exported from the DLL:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

For detailed information on converting a regular DLL that statically links to MFC to a DLL that dynamically links to MFC, see the section titled “Converting DLLTRACE to Dynamically Link with the MFC DLL” in the abstract for the DLLTRACE sample.

What do you want to do?

  • Initialize a regular DLL

What do you want to know more about?

  • Regular DLLs dynamically linked to MFC

  • Non-MFC DLLs: Overview

  • Regular DLLs statically linked to MFC: Overview

  • Extension DLLs: Overview

  • Which kind of DLL to use

  • Using extension DLL, Database/OLE/Sockets in regular DLL

  • The build settings generated by AppWizard for MFC DLLs

  • Managing the state data of MFC modules


Extension DLLs: Overview

Home | Overview | How Do I | FAQ | Details | Sample

An MFC extension DLL is a DLL that typically implements reusable classes derived from existing Microsoft Foundation Class Library classes. Extension DLLs are built using the dynamic-link library version of MFC (also known as the shared version of MFC). Only MFC executables (either applications or regular DLLs) that are built with the shared version of MFC can use an extension DLL. With an extension DLL, you can derive new custom classes from MFC and then offer this “extended” version of MFC to applications that call your DLL.

Extension DLLs can also be used for passing MFC-derived objects between the application and the DLL. The member functions associated with the passed object exist in the module where the object was created. Since these functions are properly exported when using the shared DLL version of MFC, you can freely pass MFC or MFC-derived object pointers between an application and the extension DLLs it loads.

For an example of a DLL that fulfills the basic requirements of an extension DLL, see the MFC Advanced Concepts sample DLLHUSK. In particular, look at the TESTDLL1.CPP and TESTDLL2.CPP files.

Note that the term AFXDLL is no longer used in the Visual C++ documentation. An extension DLL has the same characteristics as the former AFXDLL.

What do you want to do?

  • Initialize an extension DLL

What do you want to know more about?

  • Extension DLLs

  • Using extension DLL, Database/OLE/Sockets in regular DLL

  • Non-MFC DLLs: Overview

  • Regular DLLs statically linked to MFC: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Which kind of DLL to use

  • The build settings generated by AppWizard for MFC DLLs


Which Kind of DLL to Use

Home | Overview | How Do I | FAQ | Details | Sample

If your DLL does not use MFC, then use Visual C++ to build a non-MFC Win32 DLL. Linking your DLL to MFC (either statically or dynamically) takes up significant disk space and memory. You should not link to MFC unless your DLL actually uses MFC.

If your DLL will be using MFC, and will be used by either MFC or non-MFC applications, then you must build either a regular DLL that dynamically links to MFC or a regular DLL that statically links to MFC. In most cases, you will probably want to use a regular DLL that dynamically links to MFC because the file size of the DLL will be much smaller and the savings in memory from using the shared version of MFC can be significant. If you statically link to MFC, the file size of your DLL will be larger and it will potentially take up extra memory because it will load its own private copy of the MFC library code.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Building a DLL that dynamically links to MFC is faster than building a DLL that statically links to MFC because it is not necessary to link MFC itself. This is especially true in debug builds where the linker must compact the debug information. By linking with a DLL that already contains the debug information, there is less debug information to compact within your DLL.

One disadvantage to dynamically linking to MFC is that you must distribute the shared DLLs MFCx0.DLL and MSVCRT.DLL (or similar files) with your DLL. The MFC DLLs are freely redistributable, but you still must install the DLLs in your setup program. In addition, you must ship the MSVCRT.DLL, which contains the C run-time library that is used both by your program and the MFC DLLs themselves.

If your DLL will only be used by MFC executables, you have a choice between building a regular DLL or an extension DLL. If your DLL implements reusable classes derived from the existing MFC classes, or if you need to pass MFC-derived objects between the application and the DLL, then you must build an extension DLL.

If your DLL dynamically links to MFC, the MFC DLLs may be redistributed with your DLL. This architecture is particularly useful for sharing the class library between multiple executable files to save disk space and minimize memory usage.

Prior to version 4.0, Visual C++ only supported two kinds of DLLs that used MFC: USRDLLs and AFXDLLs. Regular DLLs statically linked to MFC have the same characteristics as the former USRDLL. MFC extension DLLs have the same characteristics as the former AFXDLLs.

What do you want to know more about?

  • Non-MFC DLLs: Overview

  • Regular DLLs statically linked to MFC: Overview

  • Regular DLLs dynamically linked to MFC: Overview

  • Extension DLLs: Overview

  • The files that must be redistributed with a DLL


Exception Handling: Overview

Home | How Do I | FAQ | Details

Exceptions occur when a program executes abnormally due to conditions outside the program's control, such as low memory or I/O errors. Abnormal situations should be handled by throwing and catching exceptions.

Abnormal situations are not the same as normal error conditions, such as a function executing correctly but returning a result code indicating an error. A normal error condition, for example, would be a file status function indicating a file doesn't exist. For normal error conditions, examine the error code and respond appropriately.

Abnormal situations are also not the same as erroneous execution, in which, for example, the caller makes some mistake in passing arguments to a function or calls it in an inappropriate context. For erroneous execution, test your inputs and other assumptions with an assertion (see The ASSERT Macro).

Visual C++ supports three kinds of exception handling:

  • C++ exceptions

  • Structured exception handling (SEH), used in C programs for Windows NT and Windows 95

  • MFC exceptions

Note Since version 3.0, MFC has used C++ exceptions but still supports its older exception handling macros, which are similar to C++ exceptions in form.

Usage Advice

In MFC programs, use C++ exceptions; don't use SEH. Use SEH only in non-MFC programs. Don't mix the two approaches. For advice on mixing MFC macros and C++ exceptions, see Exceptions: Using MFC Macros and C++ Exceptions.

What do you want to know more about?

  • When to use which kind of exception mechanism

  • C++ exceptions, the exception mechanism that is part of the C++ language

  • C++ exception handling: Synchronous exception model is now the default

  • Structured exception handling

  • Exception handling in an MFC program

  • The exception classes used in MFC database programming

  • The exception classes used in MFC OLE programming

  • Converting from the older MFC exception macros to C++ exceptions


File Handling: Overview

Home | How Do I | Details

Visual C++ supplies a number of ways to work with files, including:

  • Run-time library functions for file handling

  • Win32 API functions for file handling

  • MFC classes: CFile and its derived classes

MFC's class CFile encapsulates access to files in a C++ class. The MFC library also supplies derived classes like CStdioFile and CMemFile for working with text files, in-memory files, OLE streams, and other file-like objects, such as Windows sockets.

What do you want to know more about?

  • Creating a CFile object associated with a file

  • Opening a file with CFile

  • Reading from or writing to a file with CFile

  • Closing a file with CFile

  • Accessing file status information


Internet Support: Overview

Home | How Do I | Details | Sample

Microsoft provides many APIs for programming both client and server applications. Many new applications are being written for the Internet, and as technologies, browser capabilities, and security options change, new types of applications will be written. Browsers run on client computers, providing access to the World Wide Web and displaying HTML pages that contain text, graphics, ActiveX controls, and documents. Servers provide FTP, HTTP, and gopher services, and run server extension applications using CGI and ISAPI. Your custom application can retrieve information and provide data on the Internet.

MFC provides classes which support Internet programming. You can use COleControl and CDocObjectServer and related MFC classes to write ActiveX controls and Active documents. You can use MFC classes such as CInternetSession, CFtpConnection, and CAsyncMonikerFile to retrieve files and information using Internet protocols such as FTP, HTTP, and gopher. You can use CHttpServer and CHttpFilter and related MFC ISAPI classes to extend Web servers with custom applications and filters

What do you want to know more about?

  • Active Technology on the Internet

  • ActiveX Controls on the Internet

  • Active Documents

  • ISAPI Server Extensions and Filters

  • WinInet (HTTP, FTP, Gopher)

  • Internet Downloading Using Asynchronous Monikers


Active Technology on the Internet

Home | Overview | How Do I

Active technology is an open platform that lets developers create exciting, dynamic content and applications for the global Internet, or for a company's internal network, known as an intranet. The major new technologies provided by Microsoft for Internet programming are described below.

ActiveX Controls

ActiveX controls (formerly OLE controls) are objects that can be inserted into Web pages or any other application that is an ActiveX control container. Examples include buttons, stock tickers, and chart controls.

Active documents

Active documents can be displayed by Web browsers or document viewers. Traditional embedded objects were limited to one page and were shown embedded in the document. With Active technology, the document can be displayed full frame in the entire client area window.

Active Server Framework

You can extend a Web server to provide customized Web pages, using content from a database or customized in other ways by an application that runs on the server. The MFC ISAPI classes provide an easy way to write custom server extensions and filters.

Internet Data Download Services

Data can be downloaded over the Internet using common protocols: HTTP, FTP, and gopher. The MFC WinInet classes make it easy to transfer data using HTTP, FTP, and gopher protocols by abstracting the TCP/IP and WinSock protocols. The MFC asynchronous moniker classes provide a way to download files without blocking and to render large objects asynchronously.

Active Scripts

VBScript and other scripting languages connect controls and add interactive functionality to Web pages. Scripting moves processing from the server to the client. For example, form entries can be validated on the client and then sent to the server.

HTML Extensions

HTML extensions, such as the object tag, have been added to support controls and scripting.

See Also CHttpServer, CHttpFilter, CHtmlStream


ActiveX Controls on the Internet

Home | Overview | How Do I

ActiveX controls are the updated version of the OLE control specification. This article lists the advantages of using ActiveX controls, and requirements and design tips for ActiveX controls.

Controls are a primary architecture for developing programmable software components that can be used in a variety of different containers, including COM-aware Web browsers on the Internet. Any ActiveX control can be an Internet control and can add its functionality to an Active document or be part of a Web page. Controls on a Web page can communicate with each other using scripting.

Advantages of ActiveX Controls

ActiveX controls have several advantages, including:

  • Fewer required interfaces than previous OLE controls.

  • The ability to be windowless and always in-place active.

Requirements for an ActiveX Control

In order to be an ActiveX control, a control must:

  • Support the IUnknown interface.

  • Support additional interfaces as needed for functionality.

ActiveX Control Design Tips

Designing a control that will work well in an Internet environment requires consideration for the relatively low transmission rates on the Internet.

To improve performance of your controls, pay attention to efficiency considerations regarding:

  • Implementing the techniques described in the article ActiveX Controls: Optimization.

  • How a control is instantiated.

  • Keeping the control code size small.

    Small button and label controls, with only a few bytes of persistent data, are suitable for use in the Internet environment and work well inside browsers.

  • How persistent data is stored, both properties and large data BLOBs (such as a bitmap image or video data).

    Controls with significant amounts of persistent data, such as large bitmaps or AVI files, require careful attention to downloading method. A document or page can become visible as soon as possible, and allow the user to interact with the page while controls retrieve data in the background.

  • How components are downloaded and installed across the Internet.

    When downloading large streams such as bitmaps or video data, access a control's data asynchronously in cooperation with the container. Retrieve the data in an incremental or progressive fashion, working cooperatively with other controls that may also be retrieving data. Code can also be downloading asynchronously.

  • How progress is communicated to the container.

    Notify the container of progress in the asynchronous download, including when the user can start to interact with a page, and when the download is complete. The container can display progress (such as percent complete) to the user.

  • How controls are registered on the client computer.

For more information about the new features of ActiveX controls and how you can make them work well on the Internet, see the ActiveX Software Development Kit (SDK) documentation.

See Also Internet: Where Is..., Internet First Steps: ActiveX Controls


Active Documents

Home | Overview | How Do I

Active documents provide an extension to traditional embedded objects. The Active documents may be multipage and are displayed in the entire client area. They do traditional menu negotiation, and can be edited in-place as well as in an open window in the server application. Instead of displaying as a small rectangle surrounded by a hatched border, Active documents are full frame and always in-place active.

Active documents can be viewed in a container like the Microsoft Office Binder, which provides a way to create a compound document made up of different document types like Excel, Word, and your custom document type, each of which can be edited full frame. Active documents can also be displayed in a browser such as Microsoft Internet Explorer 3.0, which is an Active document container.

Advantages of Active Documents

Active document features include:

  • Documents can be viewed full frame, in the entire client window.

  • Documents can be opened in a separate application window.

    For the document to open, the helper application must exist on the client, or be downloaded separately before the application can run. A viewer may be written to provide limited functionality (Word, PowerPoint, and Excel provide viewers for their documents). The full version of the application can provide full editing support.

  • Documents are always in-place active.

  • Menu commands invoked from the container can be routed to your document.

  • Documents can be viewed in a Web browser. This provides seamless integration between your documents and other Web pages.

    A user can browse an HTML Web page, then an Excel spreadsheet, and then to a document that you've written using MFC support for Active documents. The user can navigate using the familiar Web interface, as the browser switches seamlessly between the menus and views of an HTML page, Excel, and your application's document.

  • All applications are displayed in a common frame.

Requirements for Active Documents

The interfaces listed in the table below include interfaces already required for embedded servers and several new interfaces specific to Active documents. MFC provides default implementations for most of these interfaces in the COleServerDoc class.

A document that . . . | Implements these interfaces
Uses compound files as its storage mechanism. | IpersistStorage.
Supports the basic embedding features of Active documents, including Create From File. | IpersistFile, IoleObject, and IDataObject.
Supports in-place activation. | IoleInPlaceObject and IoleInPlaceActiveObject (using the container's IOleInPlaceSite and IoleInPlaceFrame interfaces).
Supports the Active document extensions that involve these new interfaces. Some interfaces are optional. | IoleDocument, IOleDocumentView, IoleCommandTarget, and IPrint.

MFC provides support for extending existing embedded server support to Active documents.

What do you want to do?

  • Add Active document support to existing applications

  • See BINDSCRB, a sample illustrating the use of the new interfaces for Active documents.

See Also Internet: Where Is...


ISAPI Server Extensions and Filters

Home | Overview | How Do I

The Internet Server API (ISAPI) provides a simple and efficient way to extend any ISAPI-compliant Web server.

Advantages of ISAPI Server Extensions

You can write ISAPI server extension DLLs (ISAs) that can be loaded and called by the HTTP server. Users can fill out forms and click a submit button to send data to a Web server and invoke your ISA, which can process the information to provide custom content or store it in a database. Web server extensions can use information in a database to build Web pages dynamically, and then send them to the client computers to be displayed. Your application can add other custom functionality and provide data to the client using HTTP and HTML.

Advantages of ISAPI Filters

You can write an ISAPI filter. The filter is also a DLL that runs on an ISAPI-enabled HTTP server. The filter registers for notification of events such as logging on or URL mapping. When the selected events occur, the filter is called, and you can monitor and change the data (on its way from the server to the client or vice versa). ISAPI filters can be used to provide custom encryption or compression schemes, or additional authentication methods.

Both server extensions and filters run in the process space of the Web server, providing an efficient way to extend the server's capabilities.

What do you want to do?

  • Create an ISAPI Extension

  • Create an ISAPI Filter

What do you want to know more about?

  • Differences between filters, server extensions, and CGI

  • Using ISAPI to extend Web servers

  • Writing ISAPI Server Extensions

  • Writing ISAPI Filters

See Also Internet First Steps: ISAPI Server Extensions and Filters, Internet Server API (ISAPI) Extensions


WinInet (HTTP, FTP, Gopher)

Home | Overview | How Do I

The Microsoft Win32 Internet functions (WinInet) assist you in making the Internet an integral part of any application. The new functions, contained in WININET.DLL, simplify accessing the Internet using HTTP (Hypertext Transfer Protocol), FTP (File Transfer Protocol), and gopher.

Features of WinInet

You can use WinInet to:

  • Download HTML pages.

    HTTP is a protocol used to transfer HTML pages from a server to a client browser.

  • Send FTP requests to upload or download files or get directory listings.

    A typical request is an anonymous logon to download a file.

  • Use gopher's menu system for accessing resources on the Internet.

    Menu items can be several types, including other menus, an indexed database you can search, a newsgroup, or a file.

For all three protocols, you establish a connection, make requests to the server, and close the connection.

Advantages of WinInet

The MFC WinInet classes make it easy to:

  • Read information from HTTP, FTP, and gopher servers as easily as reading files from a hard drive.

  • Use HTTP, FTP, and gopher protocols without programming directly to WinSock or TCP/IP.

    Developers who use the Win32 Internet functions do not need to be familiar with TCP/IP or Windows Sockets. You can still program at the socket level, using WinSock and TCP/IP protocols directly, but it's even easier to use the MFC WinInet classes to access HTTP, FTP, and gopher protocols across the Internet. For many common operations, developers do not need to know the details of the particular protocol they are using.

Many operations that can be performed by your computer as a client to other computers on the Internet can take a long time. The speed of these operations is usually limited by the speed of your network connection, but they can also be affected by other network traffic and the complexity of the operation. Connecting to a remote FTP server, for example, requires that your computer first look up the name of that server to find its address. Your application will then attempt to connect to the server at that address. Once the connection is opened, your computer and the remote server will initiate a conversation with the file transfer protocol before you can actually use the connection to retrieve files.

MFC WinInet Classes

The WinInet support classes are convenient because they do all of this work for you, regardless of what protocol you're using to connect to the remote server. For example, connecting to an FTP server still requires several steps at a low level, but as an MFC developer, you only need to make one call to CInternetSession::GetFTPConnection to create that connection.

As an MFC programmer, you may have used CStdio to manage your data. The new MFC WinInet classes provide the same functionality for data that is transferred across the Internet. These classes abstract the Internet protocols for HTTP, FTP, and gopher into a high-level application programming interface, providing a fast and straightforward path to making applications Internet-aware.

What do you want to do?

  • Create an Internet client application

  • Create an FTP client application

  • Create a gopher client application

  • Create an HTTP client application

What do you want to know more about?

  • Internet First Steps: WinInet

  • Internet programming with WinInet

  • How WinInet makes it easier to create Internet client applications

  • How MFC makes it easier to create Internet client applications

  • Classes provided by MFC for creating Internet client applications

  • Prerequisites for Internet client classes

See Also Internet: Where Is..., FTPTREE Sample, TEAR Sample


Internet Downloading Using Asynchronous Monikers

Home | Overview | How Do I

The Internet requires new approaches to application design because of its slow network access. Applications should perform network access asynchronously to avoid stalling the user interface. The MFC class CAsyncMonikerFile provides asynchronous support for downloading files.

Advantages of Asynchronous Monikers

You can use asynchronous monikers to:

  • Download code and files without blocking.

  • Download properties in ActiveX controls without blocking.

  • Receive notifications of downloading progress.

  • Track progress and ready state information.

  • Provide status information to the user about progress.

  • Allow the user to cancel a download at any time.

MFC Classes for Asynchronous Monikers

CAsyncMonikerFile is derived from CMonikerFile, which in turn is derived from COleStreamFile. A COleStreamFile object represents a stream of data; a CMonikerFile object uses an IMoniker to obtain the data, and a CAsyncMonikerFile object does so asynchronously.

Asynchronous monikers are used primarily in Internet-enabled applications and ActiveX controls to provide a responsive user interface during file transfers. A prime example of this is the use of CDataPathProperty to provide asynchronous properties for ActiveX controls.

MFC Classes for Data Paths in ActiveX Controls

The MFC classes CDataPathProperty and CCachedDataPathProperty implement ActiveX control properties that can be loaded asynchronously. Asynchronous properties are loaded after synchronous initiation. Asynchronous ActiveX controls repeatedly invoke a callback to indicate availability of new data during a lengthy property exchange process.

CDataPathProperty is derived from CAsyncMonikerFile. CCachedDataPathProperty is derived from CDataPathProperty. To implement asynchronous properties in your ActiveX controls, derive a class from CDataPathProperty or CCachedDataPathProperty, and override OnDataAvailable and other notifications you wish to receive.

What do you want to do?

  • Create an ActiveX control to use on the Internet

  • Use Asynchronous Monikers to download data on the Internet


MAPI, Enabling Your Program for Mail: Overview

Home | How Do I | Details | Sample

MFC implements simple MAPI, a version of the Microsoft Messaging API that lets you easily implement a Send command to mail your documents using the mail client on the user's machine.

For more complete MAPI support, use the messaging API functions under Win32.

What do you want to know more about?

  • MFC MAPI support

  • Mail-enabling an application

See Also CDocument::OnFileSendMail, CDocument::OnUpdateFileSendMail, COleDocument::OnFileSendMail


Memory Management with MFC: Overview

Home | How Do I | Details

Manage your program's memory usage on the heap or on the stack frame under MFC.

Tip Incorrectly deallocating heap memory for an array is a common problem. See Memory Management: Examples.

What do you want to know more about?

  • MFC memory management

  • Allocating memory on the heap

  • Allocating memory on the stack frame

  • Allocating memory for an array of bytes

  • Deallocating memory for an array from the heap

  • Allocating memory for a data structure

  • Allocating memory for a C++ object

  • Allocating resizable memory blocks


Messages and Commands: Overview

Home | How Do I | Details | Tutorial

In traditional programs for Windows, Windows messages are handled in a large switch statement in a window procedure. MFC instead uses message maps to map direct messages to distinct class member functions. Message maps are more efficient than virtual functions for this purpose, and they allow messages to be handled by the most appropriate C++ object?application, document, view, and so on. You can map a single message or a range of messages, command IDs, or control IDs.

WM_COMMAND messages — usually generated by menus, toolbar buttons, or accelerators — also use the message-map mechanism. MFC defines a standard routing of command messages among the application, frame window, view, and Active documents in your program. You can override this routing if you need to.

Message maps also supply a way to update user-interface objects (such as menus and toolbar buttons), enabling or disabling them to suit the current context.

The easiest way to map messages is with ClassWizard or WizardBar.

What do you want to know more about?

General Message-Mapping Topics

  • Message mapping

  • Command routing

  • Ranges of messages, command IDs, or control IDs to a single handler

  • Updating user-interface objects as program conditions change

Advanced Message-Mapping Topics

  • Modifying the standard command routing

See Also CWnd, CCmdTarget


MFC: Overview

Home | How Do I | Details | Sample | Tutorial

The Microsoft Foundation Class Library (MFC) is an "application framework" for programming in Microsoft Windows. Written in C++, MFC provides much of the code necessary for managing windows, menus, and dialog boxes; performing basic input/output; storing collections of data objects; and so on. All you need to do is add your application-specific code into this framework. And, given the nature of C++ class programming, it's easy to extend or override the basic functionality the MFC framework supplies.

The MFC framework is a powerful approach that lets you build upon the work of expert programmers for Windows. MFC shortens development time; makes code more portable; provides tremendous support without reducing programming freedom and flexibility; and gives easy access to "hard to program" user-interface elements and technologies, like Active technology, OLE, and Internet programming. Furthermore, MFC simplifies database programming through Data Access Objects (DAO) and Open Database Connectivity (ODBC), and network programming through Windows Sockets. MFC makes it easy to program features like property sheets ("tab dialogs"), print preview, and floating, customizable toolbars.

What do you want to know more about?

  • Learning to program with MFC

  • MFC fundamentals: windows, documents, views, and more

  • A specific key area of MFC programming

  • What MFC assumes I know already

  • Where to find third-party information about programming for Windows and programming with MFC

  • What MFC can and can't do for me

For complete information about the many MFC samples shipped with Visual C++, see MFC Samples.


Learning to Program with MFC

Home | Overview | How Do I | Details | Sample | Tutorial

Tutorials for MFC

The MFC Scribble tutorial walks you through developing a simple MFC application. Each chapter explains a new class, skill, or tool. You can work along with the tutorial, or you can simply read and then try out each stage of the tutorial program.

Several other tutorials guide you through the fundamentals of OLE, ActiveX controls, and databases. See MFC Tutorials available.

Reference Information About MFC

The MFC classes are documented in the Class Library Reference. Also see the MFC hierarchy chart, which shows how the MFC classes are related to each other. The chart is also a useful tool for navigating through the class documentation.

Conceptual and How-To Information About MFC

These books cover most MFC programming information:

  • Beginning Your Program

  • Adding User-Interface Features

  • Adding Program Functionality

What do you want to do?

  • Go to the MFC Scribble tutorial for basic MFC skills.

  • Go to the COM component, container, or automation tutorials.

  • Go to the ActiveX control tutorial.

  • Go to the MFC ODBC or MFC DAO database programming tutorials.

  • Go to the Windows 95 logo guide for logo compliance information.

  • See what MFC tutorials are available.

  • See what's in the MFC Class Library Reference.

  • Learn about beginning an MFC program?or any other kind of program.

  • Learn about adding user-interface features such as menus, toolbars, and dialog boxes.

  • Learn about adding the code that makes my program unique?the code that, for example, calculates spreadsheet data, formats text, or runs a database query.


MFC Tutorials Available

Home | Overview | How Do I | Sample

For a tour of the MFC development process with real applications, see the tutorials:

  • The Scribble Tutorial shows you how to use the basic MFC framework.

  • The COM component, Container, and Automation tutorials teach OLE and Automation programming techniques.

  • The ActiveX control tutorial explains ActiveX control development.

  • The ODBC database tutorial explains ODBC database programming techniques.

  • The DAO database tutorial explains DAO database programming.

While it is possible to do these tasks by hand or using other tools, your savings in time, energy, and errors suggest that using the tools and framework is greatly to your benefit.

In addition to the tutorials listed above, see Windows 95 Functionality for a guide to Windows 95 logo compliance.


The Assumptions of MFC

Home | Overview | How Do I | Details | Sample | Tutorial

Among the important assumptions made by the MFC documentation are that:

  • You already know a little about programming for Windows.

  • You know the basics of programming in C++.

  • You understand the fundamentals of object-oriented programming.

What do you want to do?

  • Learn where to find third-party information about MFC programming

  • Find out how to start learning MFC

  • Get an overview of MFC fundamentals


Books That Help You Learn MFC

Home | Overview | How Do I | Details | Sample | Tutorial

The MFC tutorials teach you only some of the things you need before you can really master MFC itself. You will also want to consult books such as the following:

Book | What it covers
Scot Wingo and George Shephard's MFC Internals (Addison Wesley) | MFC implementation details.
Mike Blaszczak's The Revolutionary Guide to Win32 Programming Using Visual C++ (WROX Press) | MFC usage and other Visual C++ product information.
Jeff Prosise's Programming Windows 95 with MFC (Microsoft Press) | For Win32 SDK Windows programmers and C++ programmers new to MFC.
Adam Denning's ActiveX Controls Inside Out, Second Edition (Microsoft Press) | Develop MFC-based ActiveX controls using COM technology.
Frank Crockett's MFC Developer's Workshop (Microsoft Press) | Solutions for commonly-encountered coding problems: interface elements, ActiveX controls, databases, and more.
David J. Kruglinski's Inside Visual C++ (Microsoft Press) | MFC fundamentals.
Mastering MFC Development (Microsoft Press) | A compact disc (CD) that trains you to use MFC and the Visual C++ development system.

Many good books are also available on C++ and object-oriented programming.

For the assumptions that MFC makes about your knowledge and skills, see The Assumptions of MFC.

Other Learning Sources About MFC

For an online, interactive introduction to programming with Visual C++, including MFC, see the Mastering Visual C++ product.

What do you want to do?

  • Find out how to start learning MFC

  • Get an overview of MFC fundamentals


MFC Fundamentals

Home | Overview | How Do I | Details | Sample | Tutorial

MFC's strong suit is its fundamental support for programming for Microsoft Windows. The following programming areas are of common interest:

Frame windows

Documents

Views of documents

Multiple views

Special view types, such as scroll views and form views

Dialog boxes and property sheets

Windows Common Controls

Mapping Windows messages to handler functions

Toolbars and other control bars

Printing and print preview

Serialization of data to and from files and other media

Device contexts and GDI drawing objects

Exception handling

Collections of data objects

Diagnostics

Strings, rectangles, and points

Date and time

And considerably more.

What do you want to do?

  • Find out how to start learning MFC

  • Learn where to find third-party information about MFC programming


Key MFC Programming Areas

Home | Overview | How Do I | Details | Sample | Tutorial

What MFC Can't Do for You

As a general programming framework, MFC can't anticipate every programmer's every need. For example, MFC makes it easy to build the interface for a spreadsheet application, but you must provide all of the important display and computation logic.

Note MFC is not a general function library, like the C run-time library. You cannot simply call MFC class member functions in an otherwise non-MFC context. From within MFC, you can still call Win32 API functions directly, particularly those that MFC does not choose to encapsulate. But most MFC functions are members of a class, and you must have an object of the class before you can call any of its member functions. For related information, see Win32 Programming: Overview.

What MFC Can Do for You

Despite its generality, MFC does support you in many specialized ways:

Support For | See
OLE visual editing | OLE in MFC: Overview
Automation | Automation: Overview
ActiveX Controls | ActiveX Controls: Overview
Internet programming | Internet Support: Overview
Windows Common Controls | Controls: Overview
DAO Database Programming | Databases: Overview
ODBC Database Programming | Databases: Overview
Multithreaded Programming | Multithreaded Programs: Overview
Network Programming | Windows Sockets for Network Programming: Overview
Portability | Porting and Upgrading Home Page

What do you want to do?

  • Find out how to start learning MFC

  • Get an overview of MFC fundamentals


Mixed-Language Programming: Overview

Home | How Do I | Details

Mixed-language programming is the process of building programs in which the source code is written in two or more languages. Although mixed-language programming presents some additional challenges, it is worthwhile because it enables you to call existing code that may be written in another language.

Microsoft provides 32-bit versions of C, C++, MASM, and Fortran, and mixed-language programming is possible between all these languages. Mixed-language programming for Win32 is not the same as for 16-bit environments, but in many respects it is simpler. This chapter describes important mixed-language programming considerations.

What do you want to know more about?

  • Mixed-language programming issues

  • Calling routines in one language from another

  • Building mixed-language programs

  • Working with data types between two languages


Multibyte Character Sets (MBCS): Overview

Home | How Do I | Details

Multibyte character sets (MBCS) are an alternative to Unicode for supporting character sets, like Japanese and Chinese, that cannot be represented in a single byte. If you are programming for an international market, consider using either Unicode or MBCS, or enabling your program so you can build it for either by changing a switch.

The most common MBCS implementation is double-byte character sets (DBCS). Visual C++ in general, and MFC in particular, is fully enabled for DBCS.

For samples, see the MFC source code files.

What do you want to know more about?

  • What MBCS is

  • When to use MBCS

  • Support in Visual C++ for MBCS

  • The Input Method Editor (IME)

  • How to program for MBCS


Multithreaded Programs: Overview

Home | How Do I | Details | Sample

Using the Win32 API or MFC, you can create programs for Windows 95 and Windows NT that use multiple threads of execution to achieve concurrency. You might, for example, place the code for a background process (such as printing or spreadsheet calculations) in a separate thread. MFC supplies classes for threads and for synchronizing multiple threads that share resources.

What do you want to know more about?

  • Multithreading

  • Thread-safe classes

  • Multithreaded programming using MFC

  • Multithreaded programming using only the Win32 API

  • Semaphores, mutexes, and critical sections for thread synchronization

  • Thread-local storage issues

  • Worker threads

  • User-interface threads

  • Starting a thread

  • Terminating a thread

  • Accessing objects from multiple threads

  • Accessing MFC objects from non-MFC threads

  • Windows handle maps in threads

  • Communicating between threads

See Also CWinThread, CSyncObject, CSemaphore, CMutex, CCriticalSection, CEvent, CMultiLock, CSingleLock


OLE in MFC: Overview

Home | How Do I | Details | Sample | Tutorial

MFC provides the easiest way to write programs that use OLE:

  • For OLE visual editing (in-place activation)

  • To work as OLE containers or servers

  • To implement drag-and-drop functionality

  • To work with date and time data

  • To manage the state data of MFC modules, including exported DLL function entry points, OLE/COM interface entry points, and window procedure entry points

You can also use Automation or Remote Automation to operate another program from your program.

What do you want to know more about?

  • OLE in MFC

  • OLE without MFC

  • OLE visual editing applications

  • Containers

  • COM components

  • Container/server COM components

  • Drag and drop support

  • Automation servers

  • Automation clients

  • Remote Automation

  • Windows 95 logo compliance

See Also Connection Points


Reusing Code: Overview

Home | How Do I | Details

The Gallery stores code for later sharing or reuse. Such code can be wizards; ActiveX controls; HTML, text, or graphics files (including .BMP, .GIF, or .JPG); or shared classes that you have added to the Gallery from your own projects (using applicable languages).

You can enhance your projects by using items from the Gallery. The Gallery comes with default folders containing prepackaged Visual C++ Components and Registered ActiveX Controls.

You can also add items to the Gallery, and organize the contents of the Gallery by performing ordinary Explorer tasks such as creating new folders, and moving items between folders. You can also use specific language packages to build your own reusable Gallery components. A component need not be part of a project to reside in the Gallery.

What do you want to know more about?

  • Reusing code (using the Gallery)

  • Accessing and viewing Gallery contents

  • Adding a Gallery item to a project

  • Adding items to the Gallery

  • Organizing Gallery items

  • The Registered ActiveX Controls folder

  • The Visual C++ Components folder


Serialization: Overview

Home | How Do I | Details

Use MFC's serialization mechanism to read and write the data in your program's documents. Build serialization support into your data classes. Or override MFC's serialization mechanism to store data your own way, perhaps in a database or in your own file format.

Writing data to and reading it from files is complicated because one C++ object can contain other objects or pointers to objects. Reading or writing the state of objects to persistent storage, such as a file, requires managing this complex web of objects. (For more information, see CArchive Tasks.)

MFC serialization is the default solution. When serialization doesn't suit your needs, you can trace through the call stack and pick a suitable place to override the mechanism, either to alter its behavior or to replace it with your own implementation.

What do you want to know more about?

  • CDocument

  • CObject

  • Serialization — object persistence

  • MFC's serialization mechanism

  • Designing a serializable class


Strings: Overview

Home | How Do I | Details

Visual C++ provides several ways to manage string data:

  • Run-time library functions for working with C-style null-terminated strings

  • Win32 API functions for managing strings

  • MFC's class CString, which provides flexible, resizable string objects

Nearly all programs work with string data. MFC's CString class is often the best solution for flexible string handling. Both the run-time library and CString support strings containing multibyte (wide) characters, as in Unicode or MBCS programming.

What do you want to know more about?

  • CString

  • General discussion of CString

  • Converting between CString and other string types

  • CString objects as function arguments or return values

  • Unicode and MBCS support in CString

  • CString member functions that replace standard run-time functions


Templates in C++: Overview

Home | How Do I | Details

C++ templates enable you to define a family of functions or classes that can operate on different types of information. The Microsoft implementation of C++ templates is based on the ISO WG21/ANSI X3J16 working papers towards the evolving standard for C++.

Use templates in situations that result in duplication. For example, you can use function templates to create a set of functions that apply the same algorithm to different data types. Or you can use class templates to develop a set of type-safe classes. Templates are sometimes a better solution than C macros and void pointers, and they are especially useful for developing collection classes (one of the main uses for templates in MFC) and smart pointers.

What do you want to know more about?

  • What templates are

  • When to use templates

  • Using function templates

  • Using class templates

See Also Collection Class Topics


Unicode Programming: Overview

Home | How Do I | Details | Sample

Unicode is a specification for supporting character sets, like Japanese and Chinese, that cannot be represented in a single byte. If you are programming for an international market, consider using either Unicode or multibyte character sets (MBCS), or enabling your program so you can build it for either by changing a switch.

What do you want to know more about?

  • What Unicode is

  • When to use Unicode

  • Support in Visual C++ for Unicode

  • How to program for Unicode


Win32 Programming: Overview

Home | How Do I | Details

The Win32 application programming interface (API) defines the 32-bit members of the Windows operating system family from the programmer's point of view. Some members of the Windows family use the entire Win32 API, while others use subsets. For details, see Windows 95 System Limitations.

The Microsoft Foundation Class Library (MFC) encapsulates, or "wraps," much of (but not all of) the Win32 API. MFC versions 2.x and earlier encapsulated the 16-bit Windows API. In general, MFC supplies classes representing key Windows objects, such as windows, dialog boxes, brushes, pens, and fonts. The member functions of these classes wrap most of the important Win32 API functions associated with the encapsulated object. That is, the MFC class member function calls the Win32 API function (it may do other things as well).

With Visual C++, you can program for Windows using either C or C++ and the Win32 API, or using C++ and MFC. Visual C++ includes documentation for writing in C or C++ and for MFC. It also adds the Win32 SDK documentation, which is your source for most general information about programming for Windows. Aside from the Win32 SDK documents, the Visual C++ documentation focuses on what Visual C++ adds to the package: C++, MFC, and ATL. Most of the documentation you are reading is about C++ and MFC, but it frequently references the Win32 SDK for Windows concepts and techniques. If you are new to programming for Windows, reading a good third-party book is recommended.

What do you want to know more about?

  • Programming for Windows (general)

  • Programming for Windows 95

  • Programming for Windows NT

  • Programming for Win32s

  • The WINDOWS.H include file

  • STRICT type checking

  • Windows 95 logo criteria

  • Other topics on programming for Windows


Programming for Win32s

Home

Programming for the Win32s operating system is no longer supported as of Visual C++ version 4.2. To continue programming for Win32s, you must use Visual C++ version 4.1 or earlier.


Windows Sockets for Network Programming: Overview

Home | How Do I | Details | Sample

MFC supplies two classes to support programming network applications with the Windows Sockets API. Class CAsyncSocket encapsulates the Windows Sockets API one-for-one, giving advanced network programmers the most power and flexibility. Class CSocket provides a simplified interface for serializing data to and from a CArchive object.

What do you want to know more about?

  • Windows Sockets programming

  • Communication between a server socket and a client socket

  • Windows sockets and MFC archive objects

  • Deriving from a Windows Sockets class

  • Windows sockets notifications in MFC

  • Class CSocket

  • Class CAsyncSocket


Working with Classes: Overview

Home | How Do I | Details

Once you have created a project workspace, you may want to change some of the functionality, or add to it. ClassView, ClassWizard, and WizardBar are tools designed to make certain routine tasks easy. Such tasks include creating new classes, adding new member functions and variables, defining Windows message handlers, and overriding MFC virtual functions. These tools also provide a convenient way to navigate or browse through the class structure.

What do you want to know more about?

  • ClassView

  • WizardBar

  • ClassWizard

  • MFC

  • Creating a class

  • Importing a Class into ClassWizard

  • Importing the Elements of a Type Library

  • Message mapping

  • Virtual function overrides

  • Message handlers for reflected messages

  • Defining member variables for DDX, including ActiveX controls

  • Mapping a class member variable to a dialog-box control

  • Navigating my code

  • DAO or ODBC recordset classes and their associated data sources, tables, and columns

  • Database form views (record views) associated with recordsets (for DAO or ODBC)

  • Updating handler functions to update the state of any user-interface objects (menus, toolbar buttons) associated with a command ID

  • Filtering the messages available for mapping in a class

  • Adding Automation properties and methods to a class

  • Adding properties to an ActiveX control

  • Adding methods to an ActiveX control

  • Creating a handler function for an ActiveX control event


ClassView: Overview

Home | How Do I | Details

ClassView appears as a pane in the project workspace. When you open a project workspace, click the ClassView tab. ClassView shows all the C++ classes for which definitions are available, and the members of those classes. Visual C++ derives the ClassView pane from the contents of the source files included in the project workspace. The relationships in ClassView are logical relationships, not physical relationships, according to the defined class structure.


WizardBar: Overview

Home | How Do I | Details

The Universal WizardBar is a dockable toolbar that provides convenient access to ClassWizard and ClassView functionality. You use WizardBar to navigate through and perform actions on classes. WizardBar passively tracks the current context (displays the class or member function that is currently active) or actively navigates through the class structure as you do with ClassView. WizardBar also provides a menu of actions that comprise the most common navigation and editing tasks for classes.


ClassWizard: Overview

Home | How Do I | Details

ClassWizard is a Visual C++ tool that helps you create and manage the classes in your program. ClassWizard works both with the classes you create initially with AppWizard and the classes you create later with ClassWizard. ClassWizard also lets you browse and edit the classes in your program. You can create classes, map messages, override virtual functions, define Automation methods and properties, navigate through your files, and more.


Procedures for Adding Program Functionality

Home | Overview | FAQ | Details

See the following lists of how-to topics for adding non-user-interface functionality to your program:

Comprehensive List of MFC Tasks

  • MFC Tasks

Detailed Lists of Tasks, Including MFC

  • Active Technology Tasks

  • Assembler (Inline) Tasks

  • Automation Tasks

  • Calling Conventions Tasks

  • CArchive Tasks

  • Class Browsing Tasks

  • ClassView Tasks

  • ClassWizard Tasks

  • CObject Tasks

  • Collection Class Tasks

  • Connection Point Tasks

  • Database Tasks

  • Date and Time Tasks

  • DLL Tasks

  • Exception Handling Tasks

  • File-Handling Tasks

  • Internet Tasks

  • Mail-Enabling Tasks (MAPI)

  • Memory-Management Tasks

  • Menu Tasks

  • Message-Mapping Tasks

  • Multithreading Tasks

  • OLE Tasks

  • Reusing Code Tasks (using the Gallery)

  • Serialization Tasks

  • String Handling Tasks

  • Windows Sockets Tasks

  • Working with Classes Tasks

  • WizardBar Tasks


Active Technology Tasks

Home | Overview | Details

Active technology support in MFC includes ActiveX controls and Active documents (formerly known as OLE controls and OLE documents, respectively).

What do you want to do?

  • Learn more about Active technology

  • Learn more about ActiveX controls

  • Learn more about Active documents

  • Create an ActiveX control

  • Implement Active documents in my application


Assembler (Inline) Tasks

Home | Overview | Details

Visual C++ allows you to incorporate assembly language blocks inline in your C or C++ code. (See the overview for advice on when you should use inline assembler and when you should avoid it.)

What do you want to do?

  • Learn more about inline assembler and its advantages

  • Learn about the __asm keyword

  • Use assembler in my code

  • Use C or C++ inside an __asm block

  • Use and preserve registers in my assembler code

  • Jump to a label

  • Call a C function from my assembler code

  • Call a C++ function from my assembler code

  • Define an __asm block as a C macro

  • Optimize my assembler code


Automation Tasks

Home | Overview | Details | Sample | Tutorial

Automation allows one application to control another application through the methods and properties the automated target application exposes.

What do you want to do?

  • Add an Automation class

  • Add automation properties

  • Add automation methods

  • Use type libraries

  • Pass parameters in Automation

  • Access automation servers

  • Write automation clients in C++

  • Automate parts of Visual C++ from a VBScript macro

  • Use Remote Automation to automate an application over the network


Automation Sample List

Home | Overview | Details | Tutorial

See the following sample programs that illustrate Automation or Remote Automation.

Tutorial Sample

AUTOCLIK Use this sample to learn Automation techniques and as a foundation for learning Remote Automation

AUTODRIV This sample automates AUTOCLIK

Other Automation Samples

ACDUAL Adds dual interfaces to an Automation server application

CALCDRIV Automation client application driving MFCCALC

INPROC Demonstrates an In-Process Automation server application

IPDRIVE Automation client application driving INPROC

MFCCALC Demonstrates an Automation client application

Back to Automation Tasks


Calling Conventions Tasks

Home | Overview | Details

Visual C++ supplies several different function calling conventions. Understanding them helps you debug your program.

What do you want to do?

  • Learn about calling conventions

  • Use __cdecl

  • Use __stdcall

  • Use __fastcall

  • Use thiscall

  • Learn about obsolete calling conventions

  • See calling convention examples

  • Learn about naked function calls

  • Use naked function calls to write custom prolog/epilog code

  • Use the floating point coprocessor correctly


CArchive Tasks

Home | Overview | Sample

MFC class CArchive is designed to facilitate saving or loading a complex web of C++ objects to or from persistent storage. Storing objects to a file can be complex because objects often contain other objects, and two or more object pointers can point to the same object. Loading objects from a file is even more complex because the objects, and any objects they contain or reference, must be created dynamically. CArchive makes this complexity transparent to you.

Used with CFile, CArchive manages disk storage via MFC's serialization mechanism. Used with CSocketFile, CArchive manages sending or receiving data over a network via Windows Sockets. This lets you use similar interfaces for these very different data streaming tasks.

What do you want to do?

  • Serialize an object via a CArchive object

  • Create a CArchive object

  • Use CArchive << and >> operators

  • Store and load CObjects via an archive

See Also CObject, CFile, CSocketFile


Class Browsing Tasks

Home

Browse windows display information about the symbols (classes, functions, data, macros, and types) in your program. If you have browse information turned on when you build a project, the compiler creates .SBR files with information about each program file in your project. The BSCMAKE utility (BSCMAKE.EXE) assembles these .SBR files into a single browse file. This browse file has the project's base name and the extension .BSC.

Note To create a browse file, open the Settings dialog box from the Project menu. In the Browse Info tab, select the Build browse info file option. Then go to the C/C++ tab; in the General category, select Generate browse info. Then rebuild your application. For more information about BSCMAKE, see Build the Browse Information File (.BSC).

You view browse information in browse windows, which have different appearances and different controls depending on the type of information displayed.

Using browse commands, you can examine:

  • Information about all the symbols in any source file.

  • The source code line in which a symbol is defined.

  • Each source code line where there is a reference to a symbol.

  • The relationships between base classes and derived classes.

  • The relationships between calling functions and called functions.

Tip If you do not require browse information, you can speed up the build process by turning browse information off. When the browse option is off, .SBR files are not generated and the .BSC file is not updated.

What do you want to do?

  • Browse the MFC source code


Open and Close Browse Files

Home | Overview/Tasks

When you open a project workspace, the project browse file is opened automatically.

If you want to browse information on a symbol in another project, you must open the browse file for that project.

To open a browse file for another project

  1. On the File menu, click Open.

  2. In the Files of type list box, click Browse Info Files (*.bsc).

  3. Select the drive, directory, and browse file that you want.

  4. Click the Open button.

Note Some browser queries may open source files. The current browse file determines which project the browser can open source files from.

To close a browse file

  • On the Tools menu, click Close Source Browser File filename.bsc.

Tip When you use a browse information file, the .BSC file stays open for the duration of the session unless you close it. If you run NMAKE outside of the development environment, you should close the .BSC file to allow updating. If the .BSC file remains open, it cannot be updated.


Modify the Browse Window Display

Home | Overview/Tasks

A browse window appears in response to queries. For example, if you query on name CWinApp and select Definitions and References, a browse window for the CWinApp class, with all of its definitions and references, is displayed.

By default, a browse window disappears when you move the focus away from the window. You can keep the browse window in view with the pushpin button at the top of the window, as shown in the following figure.

Browse Window with Active Pushpin

Fixing a browse window on your screen with the pushpin has these two effects:

  • The browse window remains visible even if you move the focus to another window, for instance, to edit a source file.

  • The browse window remains on top of all other windows in the development environment.

To keep a browse window visible

  • Click the pushpin button at the top of the window.

To change the size of a pane in a browse window

  • With the mouse pointer, point to the split bar between panes, and drag the split bar to its new location.

To move the focus from pane to pane in a browse window

  • Press TAB to move to the next pane.

  • Press SHIFT+TAB to move to the previous pane.

Nodes in a graph display a plus sign or a minus sign in the left margin of the graph. If a node has a plus sign, you can expand that node. If a node has a minus sign, you can contract that node.

To expand or contract a node in a graph

  • Click the plus sign or minus sign.

    -or-

    Select the node with the arrow keys, and then press ENTER.


Use Browse Files

Home | Overview/Tasks

Whenever you open a project, the browse file for the project is opened if it exists. If you close the browse file, the file is reopened when you do a query.

To query the current information file about a symbol

  1. On the Tools menu, click Source Browser.

    The Browse dialog box appears.

  2. In the Identifier text box, type the name of the symbol you want to query for.

    You can use the asterisk as a wildcard to match any string.

  3. In the Select Query list box, select the type of query you want.

  4. If necessary, click the Case Sensitive Queries option.

  5. Choose OK.

    A browse window specific to the query type appears. The query results for the symbol you selected are displayed.

Tip If you select a symbol in a source file, the symbol appears in the Identifier box when you open the Browse dialog box. This eliminates step two in the procedure above.

When the browse information file is open, you can use it to find where a symbol used in a source file is defined or first referenced.

To find the definition of a symbol

  1. Select the symbol in a source file or the standard toolbar Find box.

  2. On the Edit menu, click Go To.

    The Go To dialog box appears.

  3. In the Go to what list, click Definition.

  4. Click the Go To button.

To find the first reference to a symbol

  1. Select the symbol in a source file or the standard toolbar Find box.

  2. On the Edit menu, click Go To.

    The Go To dialog box appears.

  3. In the Go to what list, select Reference.

  4. Choose the Go To button.

Note The browse file is based on the state of the source files at the time of the last build. If you edit source files and then go to a definition or a reference, the location in the browse file may no longer be accurate. If the browse file has not been built, a dialog box provides the option of building the browse file.

Tip You can jump to the previous or next definition or reference by choosing one of the navigation buttons on the Go To dialog box: Previous or Next.


Symbol Codes in the Browse Window

Home | Overview/Tasks

A browse window uses symbol codes to describe the displayed query types. For example, f V CAboutDlg::GetMessageMap(void) indicates a virtual (V) function (f).

The following table shows the codes and their meanings.

Browse Window Symbol Codes

Code | Meaning
c | Class
f | Function
d | Data
m | Macro
t | Type (other than class)
V | Virtual function
S | Static function or data member


Display the Symbols in a File

Home | Overview/Tasks

You can display an outline of all the symbols in a specific source file and filter the information that is displayed.

To display the symbols in a file

  1. Open the source file that you want to examine. If it is already open, click that window to move the focus there.

    -or-

    Select the file in the Project Workspace window.

  2. On the Tools menu, click Source Browser.

    The Browse dialog box appears.

  3. In the Select Query list box, click File Outline.

  4. Click OK.

    The File Outline browse window appears, with classes and functions displayed at the top of the left pane, as shown in the following figure.

Browse Window with File Outline

The following table describes the window elements, the function of each element, and the user's actions.

File Outline Window

Window element | Function | Action
Left pane | Lists the symbols (classes, functions, data, macros, and types) for the selected file. One or more codes identify each symbol. | Select a symbol.
Right pane | Lists the available definitions and references for the symbol selected in the left pane. | Double-click the definition or reference you want to see.
Pushpin | Determines whether or not the window is held open or allowed to close. The window remains open when the pin is pushed in. | Select to push or pull the pin.
Filter buttons | Filter the symbols shown in the current display. For more information, see Filtering Browse Information for Files. | Select to toggle filter.

Tip You can display symbols in multiple files by using the asterisk as a wildcard character in the file name. If you type a file name specification followed by the asterisk wildcard but no extension (oc*, for example), the search finds files without extensions, such as "oc1," but not files with extensions, such as "oc1.cpp."


Filtering Browse Information for Files

Home | Overview/Tasks

When you do a file outline query, five filter buttons appear at the top of the browse window. Their settings determine which symbols are displayed in the left pane of the browse window. When a button is selected (pushed in), the corresponding symbols are displayed.

To filter the symbol display

  • Select the buttons corresponding to the symbols you want to see, as shown in the following table.
    Button | Keyboard | Displays
    Classes | ALT+C | Classes
    Functions | ALT+U | Functions
    Data | ALT+A | Data symbols
    Macros | ALT+M | Macros
    Types | ALT+Y | Types (other than classes)


Display Class Information

Home | Overview/Tasks

You can view C++ class hierarchies as graphs by selecting a class and displaying either of the following two types of graphs for class hierarchies.

Derived Class Graph: All the classes that inherit attributes from the selected class.

Base Class Graph: All the classes from which the selected class inherits attributes, up to its ultimate base class, or base classes if it has multiple inheritance.

In each graph, a node represents a class.


Displaying the Graph of Classes Derived from a Class

Home | Overview/Tasks

To display a derived class graph

  1. Select the class name in a source file or the standard toolbar Find box.

  2. On the Tools menu, click Source Browser.

  3. In the Select Query list box, click Derived Classes and Members.

  4. Click OK.

    The Derived Classes And Members window appears, with the selected class name displayed at the top of the left pane. The following figure shows an example of this window.

Derived Classes and Members Window

The following table describes the window elements, the function of each element, and the user's actions.

Derived Classes and Members Window

Window element | Function | Action
Left pane | Displays the derived class graph. | Click the plus sign or minus sign to expand or contract the graph. To display information for a class, click the class name or folder icon. To open the source file for a class, double-click the class name or folder icon.
Top right pane | Displays member functions and member variables of the class selected in the left pane. | Double-click the member whose definition you want to see.
Bottom right pane | Displays available definitions and references for the symbol selected in the left pane or top right pane. | Double-click the definition or reference you want to see.
Pushpin | Determines whether or not the window disappears after it loses focus. | Select to push or pull the pin.
Help button | Displays help for the window. | Select for help.
Filter buttons | Filter the browse query to display selected types of information. For more information on filters, see Filtering Browse Information for Classes. | Select filter types from the lists.


Displaying the Base Class Graph for a Class

Home | Overview/Tasks

To display a base class graph

  1. Select the class name in a source file or the standard toolbar Find box.

  2. On the Tools menu, click Source Browser.

  3. In the Select Query list box, select Base Classes and Members.

  4. Click OK.

    The Base Classes And Members window appears, with the selected class name displayed at the top of the left pane. The following figure shows an example of this window.

Base Classes and Members Window

The following table describes the window elements, the function of each element, and the user's actions.

Base Classes and Members Window

Window element | Function | Action
Left pane | Displays the base class graph. | Click the plus sign or minus sign to expand or contract the graph. To display information for a class, click the class name or folder icon. To open the source file for a class, double-click the class name or folder icon.
Top right pane | Displays member functions and member variables of the class selected in the left pane. One or more codes identify each symbol. | Double-click the member whose definition you want to see.
Bottom right pane | Displays available definitions and references for the symbol selected in the left pane or top right pane. | Double-click the definition or reference you want to see.
Pushpin | Determines whether or not the window disappears after it loses focus. | Select to push or pull the pin.
Help button | Displays help for the window. | Select for help.
Filter buttons | Filter the browse query to display selected types of information. For more information on filters, see Filtering Browse Information for Classes. | Select filter type from the lists.

If the class has multiple inheritance, and one base class appears in more than one inheritance path, the second and subsequent instances of the class name have an ellipsis (…) after them. You cannot expand nodes that have ellipses.


Filtering Browse Information for Classes

Home | Overview/Tasks

When you open the Derived Classes and Members window, two drop-down list boxes appear at the top. You can use these lists to filter the display of information about member functions and data members.

To filter information on member functions

  • From the Functions drop-down list box, select the desired filter.
    Filter | Displays
    All | All member functions
    Virtual | Virtual member functions only
    Static | Static member functions only
    Non-Virtual | Non-virtual member functions only
    Non-Static | Non-static member functions only
    Non-Virtual Non-Static | Non-virtual, non-static member functions only
    None | No member functions

To filter information on data members

  • From the Data drop-down list box, select the desired filter.
    Filter | Displays
    All | All member data
    Static | Static member data only
    Non-Static | Non-static member data only
    None | No member data

The graphic symbols displayed in the drop-down list boxes for the function and data filters identify corresponding entries in the top right pane of the browse window.


Display Function Information

Home | Overview/Tasks

You can display the relationships among functions in your program as a graph by selecting a function and displaying either of the following two types of graphs for function relationships:

  • Call Graph: All the functions that the selected function calls.

  • Callers Graph: All the functions that call the selected function.

In each graph, a node represents a function.


Displaying a Call Graph

Home | Overview/Tasks

To display the graph of all functions that a selected function calls

  1. Select the function name in a source file or the standard toolbar Find box.

  2. On the Tools menu, click Source Browser.

  3. In the Select Query list box, click Call Graph.

  4. Click OK.

  5. If the function is an overloaded function or a member function of more than one class, the Resolve Ambiguity dialog box appears. Select the function that you want from the list.

    The Call Graph window appears, with the selected function displayed at the top of the left pane. The following figure shows the Call Graph window for a sample function.

Call Graph Window

The following table describes the window elements, the function of each element, and the user's actions.

Call Graph Window

Window element | Function | Action
Left pane | Displays the call graph for the selected function. | Click the plus sign or minus sign to expand or contract the graph. To display information for a function, click the class name or folder icon. To open the source file for a function, double-click the class name or folder icon.
Right pane | Displays a list of available definitions and references for the function selected in the left pane. | Double-click the definition or reference you want to see.
Pushpin | Determines whether or not the window disappears after it loses focus. | Select to push or pull the pin.
Help button | Displays help for the window. | Select for help.


Displaying a Graph of Calling Functions

Home | Overview/Tasks

A callers graph displays all the functions that call a selected function.

To display the graph of all functions that call a selected function

  1. Select the function name in a source file or the standard toolbar Find box.

  2. On the Tools menu, click Source Browser.

  3. In the Select Query list box, click Callers Graph.

  4. Click OK.

  5. If the function is an overloaded function or a member function of more than one class, the Resolve Ambiguity dialog box appears. Select the function that you want from the list.

    The Callers Graph window appears, with the selected function displayed at the top of the left pane. The following figure shows the Callers Graph window for a sample function.

Callers Graph Window

The following table describes the window elements, the function of each element, and the user's actions.

Callers Graph Window

Window element | Function | Action
Left pane | Displays the callers graph for the selected function. | Click the plus sign or minus sign to expand or contract the graph. To display information for a function, click the class name or folder icon. To open the source file for a function, double-click the class name or folder icon.
Right pane | Displays a list of available definitions and references for the function selected in the left pane. | Double-click the definition or reference you want to see.
Pushpin | Determines whether or not the window disappears after it loses focus. | Select to push or pull the pin.
Help button | Displays help for the window. | Select for help.


Find Definitions and References

Home | Overview/Tasks

Browse windows make it easy to move from one location of a symbol in a file to another location in another file. For instance, if you are in a source file examining the use of a symbol, you can immediately jump to the definition of that symbol. Or if you have changed the definition of a symbol, you can jump to every place in every file where the symbol is used.

Note The browse file is based on the state of the source files at the time of the last build. If you edit source files and then go to a definition or a reference, the location in the browse file may no longer be accurate. When you issue a query, if the browse file has not been built (or is not current), a dialog box is displayed with the option of building the browse file.


Displaying a Symbol Definition or Reference

Home | Overview/Tasks

Using the Browse toolbar, you can quickly display the definition or reference of a symbol. The development environment opens the source file containing the first definition or reference and highlights the symbol. To see the next definition or reference, click the Next Definition/Reference button on the toolbar.

To display the definition or reference of a symbol using the Browse toolbar

  1. Select the symbol in a source file or the standard toolbar Find box.

    You can use the asterisk as a wildcard to match any string.

  2. On the Browse toolbar, click either the Go To Definition or Go To Reference button.

  3. If the symbol is a member of more than one class, the Resolve Ambiguity dialog box appears. Select the symbol that you want from the list.

To display the definition or reference of a symbol using the right mouse button

  1. Point to the symbol in a source file (either a text editor window or the pane containing ClassView), and click the right mouse button.

  2. On the pop-up menu, click either Go To Definition or Go To Reference.

To display the definition or reference of a symbol using the Go To dialog box

  1. On the Edit menu, click Go To.

  2. In the Go to what list box, click either Definition or Reference.

  3. Enter the additional selection criteria.

  4. Click one of the navigation buttons: Go To, Previous, or Next.

To display the definition or reference of a symbol using the Definitions And References window

  1. Select the symbol in a source file or the standard toolbar Find box.

    You can use the asterisk as a wildcard to match any string.

  2. On the Tools menu, click Source Browser.

  3. In the Select Query list box, click Definitions And References.

  4. Click OK.

  5. If the symbol is a member of more than one class, the Resolve Ambiguity dialog box appears. Select the symbol that you want from the list.

  6. In the Definitions And References window, double-click the definition or reference you want to see.

    The Definitions And References window appears, with the selected symbol displayed at the top of the left pane. The following figure shows an example.

Definitions and References Window

The following table describes the Definitions And References window elements, the function of each element, and the user's actions.

Definitions and References Window

Window element | Function | Action
Left pane | Displays the selected symbol, or a list of the matching symbols if you used a wildcard. If the symbol is not fully qualified, it is followed by the symbol's type. | To display information for a symbol, click the symbol name. To open the source file for a symbol, double-click the class name or folder icon.
Right pane | Displays definitions and references for the symbol currently selected in the left pane. | Double-click the definition or reference you want to see.
Pushpin | Determines whether or not the window disappears after it loses focus. | Select to push or pull the pin.
Help button | Displays help for the window. | Select for help.

Note The browse file is based on the state of the source files at the time of the last build. If you edit source files and then go to a definition or a reference, the location in the browse file may no longer be accurate. When you issue a query, if the browse file has not been built (or is not current), a dialog box is displayed with the option of building the browse file.


CObject Tasks

Home | Overview | FAQ | Details

The following tasks involve deriving your own classes from MFC's CObject class, the root class of the class hierarchy. Deriving your class from CObject gives your class some powerful capabilities ? see the overview for more information.

What do you want to do?

  • Derive a class from CObject

  • Access run-time class information

  • Create objects dynamically


Collection Class Tasks

Home | Overview | Details | Sample | Tutorial

The following tasks involve using MFC's collection classes to manage lists, maps, and arrays of objects or other data types. It is recommended that you use the template-based collection classes, but the older non-template classes are supported for backward compatibility.

The following categories of tasks are listed in this topic:

  • Performing General Collection-Class Tasks

  • Performing Template-Based Collection-Class Tasks

  • Accessing the Members of a Collection (Template-Based or Not)

What do you want to do?

General Collection-Class Tasks

  • Choose a collection class

  • Make a type-safe collection class

  • Serialize the elements of a collection

  • Use non-template collection classes

  • Create a stack collection

  • Create a queue collection

Template-Based Collection-Class Tasks

  • Use collection classes based on templates

  • Use typed-pointer collection class templates

  • Implement helper functions for template-based collection classes

Accessing the Members of a Collection (Template-Based or Not)

  • Access all members of a collection

  • Iterate a collection

  • Delete all objects in a CObject collection

  • Delete all elements in an array collection class

  • Delete all elements in a map collection class

  • Delete all elements in a list collection class


Connection Point Tasks

Home | Overview | Details

Connection points allow an object to expose its capability to call specific interfaces. COM exposes incoming calls via the interfaces an object exposes. Connection points give COM objects the ability to expose outgoing calls as well.

What do you want to do?

  • Implement connection points


Database Tasks

Home | Overview | Details | ODBC Driver List

MFC provides two ways to work with databases. See the overview for this topic for information on choosing the right one for your needs. Also see the overview if you prefer to use either the DAO Software Development Kit (SDK) or the ODBC SDK without using MFC.

The tasks below are based on MFC.

What do you want to do?

  • Write a program that uses DAO

  • Write a program that uses ODBC

  • Write a program that uses data-bound controls

Tip Visual C++ includes the Microsoft Knowledge Base, which you can use to find additional articles on database topics written by product support engineers.


Find Microsoft Knowledge Base Articles on Database Topics

To find Knowledge Base (KB) articles on MFC ODBC topics, search the KB on the keyword MFCDATABASE.

To find KB articles on MFC DAO topics, search the KB on the keyword MFCDAO.


DAO Database Tasks

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These tasks are based on the MFC DAO classes. For information about using DAO without MFC, see Data Access Object Hierarchy Chart and the topics that follow it in Microsoft Data Access Objects, the programmer's reference with the DAO Software Development Kit (SDK). Open the DAO help file to locate these topics.

Additional help is available from the Microsoft Knowledge Base: Find Microsoft Knowledge Base articles on DAO.

The following are categories of task topics. Tasks in each category are listed in subsequent topics.

What do you want to do?

  • Install and Get Started with DAO

  • Design and Create a DAO Database Application

  • Use Database Forms (Record Views) with DAO

  • Work with DAO Objects

  • Make DAO Queries

  • Use DAO Recordsets

  • Use DAO Tabledefs

  • Use DAO Workspaces

  • Access ODBC and Other External Data Sources

  • Improve DAO Performance


Installing and Getting Started with DAO

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics help you install the necessary components to work with Data Access Objects (DAO).

What do you want to do?

  • Install MFC DAO database support


Design and Create a DAO Database Application

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics discuss designing your DAO database application.

What do you want to do?

  • Find Microsoft Knowledge Base articles on DAO

  • Write an MFC DAO application

  • Create a project with DAO database support

  • Choose MFC DAO options

  • Bind recordset fields to table columns

  • Remove columns from a recordset

  • Add columns to a recordset


Use Database Forms (Record Views) with DAO

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

Some applications, such as data entry or data viewing, require a form, a view with dialog-style controls.

What do you want to do?

  • Create a database form

  • Create a record view associated with a recordset

  • Map database form controls to a recordset

  • Set the "foreign class" associated with a record view


Work with DAO Objects

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics teach you the fundamentals of working with DAO objects: creating, opening, closing, and destroying them, and obtaining information about them.

What do you want to do?

  • Learn about constructing DAO objects in two stages

  • Create DAO objects

  • Open DAO objects

  • Close DAO object

  • Access implicit DAO objects created by MFC

  • Access "collections" in DAO objects

  • Obtain information about a DAO object


Make DAO Queries

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain using DAO querydef objects to encapsulate SQL queries.

What do you want to do?

  • Create a query from a DAO querydef

  • Create a query with a DAO recordset

  • Use querydefs

  • Parameterize a DAO query

  • Create a DAO querydef

  • Save a DAO querydef

  • Open a previously saved DAO querydef

  • Use a temporary DAO querydef

  • Create a recordset from a DAO querydef

  • Execute a DAO querydef

  • Run an SQL pass-through query in DAO


Use DAO Recordsets

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain working with records in a DAO database using recordset objects.

What do you want to do?

General DAO Recordset Tasks

  • Choose a DAO recordset type

  • Create a DAO recordset

  • Create a recordset from a DAO querydef

Recordset Design and Implementation:

  • Learn about DAO record field exchange (DFX)

  • Use DFX

  • Customize DAO recordset code produced by the wizards

  • Override CDaoRecordset::DoFieldExchange

  • Initialize DAO recordset field data members

  • Use the DAO record field exchange (DFX) functions

Recordset Performance and Convenience:

  • Improve DAO recordset performance

  • Cache multiple records with DAO for performance

  • Double buffer a DAO recordset

Recordset Operations and Navigation:

  • Add a record to a DAO recordset

  • Edit a record in a DAO recordset

  • Delete a record in a DAO recordset

  • Requery a DAO recordset

  • Filter a DAO recordset

  • Navigate through records in a DAO recordset

  • Seek a record in an indexed table-type DAO recordset

  • Find records in a DAO recordset

  • Use bookmarks in a DAO recordset

  • Use absolute positioning in a DAO recordset

  • Use percent positioning in a DAO recordset

Dynamic Binding of Recordsets:

  • Use CDaoRecordset directly, without deriving a recordset class

  • Dynamically bind data to a DAO recordset

  • Dynamically set parameters to a DAO recordset

  • Dynamically get parameter values from a DAO recordset


Use DAO Tabledefs

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain managing tables via DAO tabledef objects.

What do you want to do?

  • Learn about DAO tabledefs

  • Create a DAO tabledef

  • Open a DAO tabledef

  • Create a table-type DAO recordset

  • Examine a database schema at run time with DAO


Use DAO Workspaces

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain working with DAO database and workspace objects, particularly for managing transactions.

What do you want to do?

General Workspace Tasks

  • Use DAO workspaces

  • Explicitly open the DAO default workspace

Database Engine:

  • Access the DAO database engine

  • Initialize the DAO database engine

  • Uninitialize the DAO database engine

  • Access properties of the DAO database engine

Transactions:

  • Manage transactions in DAO

  • Open a separate DAO transaction space


Access ODBC and Other External Data Sources

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain accessing ODBC data sources external to the Microsoft Jet database engine.

What do you want to do?

  • Work with ODBC and other external data sources via DAO

  • Attach an external table to a Jet database via DAO

  • Open an external database directly via DAO

  • Create an external table via DAO

  • Refresh or remove a link to an attached table via DAO

  • Improve performance with ODBC data sources from DAO


Improve DAO Performance

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain how to improve your DAO application's performance.

What do you want to do?

  • Improve performance of DAO applications

  • Improve performance with ODBC data sources from DAO

  • Improve DAO recordset performance


DAO Database Sample List

Home | Overview | FAQ | Details | Tutorial | ODBC Driver List

See the following sample programs that illustrate Data Access Objects (DAO) functionality in MFC.

DAO Tutorial Sample

  • DAOENROL

Other DAO Samples

  • DAOCTL ActiveX control container with databound control

  • DAOTABLE MFC DAO classes used to create common database objects

  • DAOVIEW Database browser written with DAO

Back to DAO Database Tasks


ODBC Database Tasks

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These tasks are based on the MFC ODBC classes. For more information about using the ODBC API without MFC, see "Programming ODBC" in the ODBC SDK.

Find Microsoft Knowledge Base articles on ODBC

What do you want to do?

(The following are categories of task topics. Tasks in each category are listed in subsequent topics.)

  • Install and Get Started with ODBC

  • Design and Create an ODBC Database Application

  • Use Database Forms (Record Views) with ODBC

  • Use ODBC to Work with Other Users

  • Work with ODBC Database Connections

  • Work with ODBC and Drivers

  • Use the ODBC Cursor Library

  • Use MFC ODBC Recordsets


Installing and Getting Started with ODBC

Home | Overview | Details | Sample | Tutorial | Driver List

These topics help you install the components you need to start working with Open Database Connectivity (ODBC).

What do you want to do?

  • Install MFC ODBC database support

  • Install the ODBC drivers that ship with Visual C++

  • Redistribute ODBC components to your customers


Design and Create an ODBC Database Application

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics help you design and set up your ODBC database application.

What do you want to do?

  • Find Microsoft Knowledge Base articles on ODBC

  • Create a project with ODBC database support

  • Choose MFC ODBC options

  • Bind recordset fields to table columns

  • Remove columns from a recordset

  • Add columns to a recordset


Use Database Forms (Record Views) with ODBC

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

Some applications, such as data entry or data viewing, require a form, a view with dialog-style controls.

What do you want to do?

  • Display database data in a form

  • Create a database form

  • Create a record view associated with a recordset

  • Map database form controls to a recordset

  • Set the "foreign class" associated with a record view


Use ODBC to Work with Other Users

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

Use ODBC in environments where multiple users are working with the same ODBC database.

What do you want to do?

  • Work in a multiuser environment with MFC ODBC


Work with ODBC Database Connections

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain how to connect to ODBC data sources.

What do you want to do?

  • Manage ODBC database connections

  • Configure ODBC database connections

  • Programmatically configure an ODBC data source

  • Generalize an MFC ODBC connect string

  • Connect to a specific ODBC data source

  • Disconnect from an ODBC data source

  • Reuse a CDatabase object


Work with ODBC and Drivers

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

ODBC allows you to write applications that are not dependent on just one database management system (DBMS). You can write one application that can operate on multiple DBMSs for which your users have the correct DBMS-specific ODBC driver.

What do you want to do?

  • Determine the schema of an ODBC data source at run time

  • Get a driver description using ODBC Administrator

  • Obtain online help for your ODBC driver

  • Programmatically create a table in an ODBC data source

  • Call ODBC API functions directly in MFC


Use the ODBC Cursor Library

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

ODBC manages scrolling through recordsets via the Cursor Library. These topics explain how to work with the Cursor Library.

What do you want to do?

  • Use the ODBC cursor library

  • Disable the ODBC cursor library for a dynaset


Use MFC ODBC Recordsets

Home | Overview | FAQ | Details | Sample | Tutorial | ODBC Driver List

These topics explain how to work with ODBC recordsets via MFC.

What do you want to do?

General Recordset Tasks:

  • Choose an ODBC recordset type

  • Create an ODBC recordset

  • Set recordset options

  • Select records from an ODBC data source

  • Open a recordset

  • Requery a recordset

  • Close a recordset

  • Declare a recordset class for a table

  • Declare a recordset class for a predefined query

Recordset Design and Implementation:

  • Learn about record field exchange (RFX)

  • Exchange data between a database and a recordset object

  • Customize recordset code produced by the wizards

  • Override CRecordset::DoFieldExchange

  • Initialize recordset field data members

  • Use the record field exchange (RFX) functions

Recordset Performance and Convenience:

  • Add records in bulk with a recordset

  • Filter records in a recordset

Recordset Operations:

  • Determine whether a recordset is updatable

  • Add a record to a recordset

  • Add records in bulk with a recordset

  • Edit a record in a recordset

  • Delete a record in a recordset

  • Requery a recordset

  • Filter records in a recordset

  • Sort records in a recordset

  • Parameterize a recordset

  • Pass parameter values to a recordset at run time

  • Perform a join with a recordset

  • Lock records in a recordset

  • Work with large data items in a recordset

  • Obtain SUMs and other aggregate results in a recordset

Recordset Selection and SQL:

  • Select records from an ODBC data source

  • Affect how a recordset selects records

  • Customize the SQL string for a recordset

Recordset Navigation:

  • Scroll (navigate) through a recordset

  • Use bookmarks in a recordset

  • Use absolute positioning in a recordset

Dynamic Binding of Recordsets:

  • Bind data columns in a recordset dynamically at run time


ODBC Database Sample List

Home | Overview | FAQ | Details | Tutorial | ODBC Driver List

See the following sample programs that illustrate Open Database Connectivity (ODBC) functionality.

ODBC Tutorial Sample

  • ENROLL Demonstrates MFC ODBC fundamentals

Other ODBC Samples

  • CATALOG Makes calls directly to ODBC API functions

  • CATALOG2 Shows how to browse an ODBC data source schema

  • DYNABIND Demonstrates dynamic binding of database columns to a recordset

  • ODBCINFO Retrieves ODBC driver capabilities

  • STDREG Dynamically modifies student registration database used with ENROLL tutorial sample

Back to ODBC Database Tasks


Date and Time Tasks

Home | Overview | Details

Use MFC classes for time and date data, or use alternatives such as C run-time functions or Win32 API functions. For more information about alternative support for time and date operations, see Time Management in the Run-Time Library Reference and Time in the Win32 Programmer's Reference.

CTime and CTimeSpan are for use in general situations. COleDateTime and COleDateTimeSpan are for use with Automation and with the MFC database classes.

What do you want to do?

Get the Time

  • Get the current time with CTime

  • Use SYSTEMTIME with CTime to work with the system time

  • Get the current time with COleDateTime

Calculate Elapsed Time

  • Calculate elapsed time with CTimeSpan

  • Calculate elapsed time with COleDateTimeSpan

Format Time/Date Strings

  • Format a string representation of a time or elapsed time

  • Format a string representation of a time or elapsed time (Active technology)


DLL Tasks

Home | Overview | FAQ | Details | Sample

Use the following list to locate information on a DLL-related task.

What do you want to do?

  • Export from a DLL
    • Export from a DLL using .DEF files

    • Export from a DLL using __declspec(dllexport)

    • Export and import using AFX_EXT_CLASS

    • Export C++ functions for use in C-language executables

    • Export C functions for use in C or C++-language executables

    • Determine which exporting method to use

    • Export functions from a DLL by ordinal rather than by name
  • Import into an application using __declspec(dllimport)

  • Link an executable to a DLL
    • Link implicitly

    • Link explicitly

    • Determine which linking method to use
  • Initialize a DLL
    • Initialize regular DLLs

    • Initialize extension DLLs

    • Initialize non-MFC DLLs
  • Create a resource-only DLL


Export from a DLL

Home | Overview | How Do I | FAQ | Details | Sample

A .DLL file has a layout very similar to an .EXE file, with one important difference ? a DLL file contains an exports table. The exports table contains the name of every function that the DLL exports to other executables. These functions are the entry points into the DLL; only the functions in the exports table can be accessed by other executables. Any other functions in the DLL are private to the DLL. The exports table of a DLL can be viewed by using the tool DUMPBIN with the /EXPORTS switch.

You can export functions from a DLL with two methods:

  • Create a module definition (.DEF) file and use the .DEF file when building the DLL. (Use this approach if you want to export functions from your DLL by ordinal rather than by name.)

  • Use the keyword __declspec(dllexport) in the function’s definition.

When exporting functions with either method, make sure to use the __stdcall calling convention.

What do you want to do?

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Export C functions for use in C or C++-language executables

  • Determine which linking method to use

  • Import into an application using __declspec(dllimport)

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • Importing and exporting inline functions

  • Mutual imports


Export from a DLL Using .DEF Files

Home | Overview | How Do I | FAQ | Details | Sample

A module-definition (.DEF) file is a text file containing one or more module statements that describe various attributes of a DLL. If you are not using the __declspec(dllexport) keyword to export the DLL’s functions, then the DLL requires a .DEF file.

A minimal .DEF file must contain the following module-definition statements:

  • The first statement in the file must be the LIBRARY statement. This statement identifies the .DEF file as belonging to a DLL. The LIBRARY statement is followed by the name of the DLL. The linker places this name in the DLL's import library.

  • The EXPORTS statement lists the names and, optionally, the ordinal values of the functions exported by the DLL. You assign the function an ordinal value by following the function’s name with an at sign (@) and a number. When you specify ordinal values, they must be in the range 1 through N, where N is the number of functions exported by the DLL. If you wish to export functions by ordinal, see Export Functions From a DLL By Ordinal Rather Than By Name as well as this topic.

  • Although not required, typically a .DEF file also contains a DESCRIPTION statement that describes the purpose of the DLL.

For example, a DLL that contains the code to implement a binary search tree might look like the following:

LIBRARY   BTREE
DESCRIPTION "Implements a binary tree."
EXPORTS
   Insert   @1
   Delete   @2
   Member   @3
   Min   @4

If you use AppWizard to create an MFC DLL, AppWizard creates a skeleton .DEF file for you and automatically adds it to your project. Add the names of the functions to be exported to this file. For non-MFC DLLs, you must create the .DEF file yourself and add it to your project.

If you are exporting functions in a C++ file, you will have to either place the decorated names in the .DEF file or define your exported functions with standard C linkage by using extern “C”. If you need to place the decorated names in the .DEF file, you can obtain them by using the tool DUMPBIN or by using the linker switch /MAP. Note that the decorated names produced by the compiler are compiler specific. If you place the decorated names produced by the Visual C++ compiler into a .DEF file, applications that link to your DLL must also be built using the same version of Visual C++ so that the decorated names in the calling application match the exported names in the DLL’s .DEF file.

If you are building an extension DLL, and exporting using a .DEF file, place the following code at the beginning and end of your header files that contain the exported classes:

#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA

These lines ensure that MFC variables that are used internally or that are added to your classes are exported (or imported) from your extension DLL. For example, when deriving a class using DECLARE_DYNAMIC, the macro expands to add a CRuntimeClass member variable to your class. Leaving out these four lines may cause your DLL to compile or link incorrectly or cause an error when the client application links to the DLL.

When building the DLL, the linker uses the .DEF file to create an export (.EXP) file and an import library (.LIB) file. The linker then uses the export file to build the .DLL file. Executables that implicitly link to the DLL link to the import library when they are built.

Note that MFC itself uses .DEF files to export functions and classes from the MFCx0.DLL.

What do you want to do?

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Export C functions for use in C or C++-language executables

  • Determine which exporting method to use

  • Import into an application using __declspec(dllimport)

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • .DEF files

  • Rules for module-definition statements

  • Decorated names

  • Importing and exporting inline functions

  • Mutual imports


Export from a DLL Using __declspec(dllexport)

Home | Overview | How Do I | FAQ | Details | Sample

You can export data, functions, classes, or class member functions from a DLL by using the __declspec(dllexport) keyword. If you use __declspec(dllexport), you do not need a .DEF file for exports.

To export functions, the __declspec(dllexport) keyword must appear to the left of the calling-convention keyword, if a keyword is specified. For example:

__declspec(dllexport) void __cdecl Function1(void);

To export all the public data members and member functions in a class, the keyword must appear to the left of the class name as follows:

class __declspec(dllexport) CExampleExport : public CObject
{ ... class definition ... };

When building your DLL, you typically create a header file that contains the function prototypes and/or classes you are exporting, and add the __declspec(dllexport) to the declarations in the header file. To make your code more readable, define a macro for __declspec(dllexport) and then use the macro with each symbol you are exporting:

#define DllExport   __declspec( dllexport )

__declspec(dllexport) stores function names in the DLL’s export table. If you want to optimize the table’s size, see Export Functions From a DLL By Ordinal Rather Than By Name.

Note When porting DLL source code from Win16 to Win32, replace each instance of __export with __declspec(dllexport).

What do you want to do?

  • Export from a DLL using .DEF files

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Export C functions for use in C or C++-language executables

  • Determine which exporting method to use

  • Import into an application using __declspec(dllimport)

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • Using __declspec(dllimport) and __declspec(dllexport)

  • The __declspec keyword

  • Importing and exporting inline functions

  • Mutual imports

  • How to export data from a DLL

  • How to share data in my DLL with an application or with other DLLs


Export and Import Using AFX_EXT_CLASS

Home | Overview | How Do I | FAQ | Details | Sample

Extension DLLs use the macro AFX_EXT_CLASS to export classes; the executables that link to the extension DLL use the macro to import classes. With the AFX_EXT_CLASS macro, the same header file(s) used to build the extension DLL can be used with the executables that link to the DLL.

In the header file for your DLL, add the AFX_EXT_CLASS keyword to the declaration of your class as follows:

class AFX_EXT_CLASS CMyClass : public CDocument
{
// <body of class>
};

This macro is defined by MFC as __declspec(dllexport) when the preprocessor symbols _AFXDLL and _AFXEXT are defined. But the macro is defined as __declspec(dllimport) when _AFXDLL is defined and _AFXEXT is not defined. When defined, the preprocessor symbol _AFXDLL indicates that the shared version of MFC is being used by the target executable (either a DLL or an application). When both _AFXDLL and _AFXEXT are defined, this indicates that the target executable is an extension DLL.

Because AFX_EXT_CLASS is defined as __declspec(dllexport) when exporting from an extension DLL, you can export entire classes without placing the decorated names for all of that class’s symbols in the .DEF file. This method is used by the MFC Advanced Concepts sample DLLHUSK.

Although you can avoid creating a .DEF file and all the decorated names for the class with this method, creating a .DEF file is more efficient because the names can be exported by ordinal. To use the .DEF file method of exporting, place the following code at the beginning and end of your header file:

#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA

Caution Be careful when exporting inline functions, because they can create the possibility of version conflicts. An inline function gets expanded into the application code; therefore, if you later rewrite the function, it does not get updated unless the application itself is recompiled. (Normally, DLL functions can be updated without rebuilding the applications that use them.)

Exporting Individual Members in a Class

Sometimes you may want to export individual members of your class. For example, if you are exporting a CDialog-derived class, you might only need to export the constructor and the DoModal call. You can use AFX_EXT_CLASS on the individual members you need to export.

For example:

   class CExampleDialog : public CDialog
   {
   public:
     AFX_EXT_CLASS CExampleDialog();
     AFX_EXT_CLASS int DoModal();
     ...
     // rest of class definition
     ...
   };

Because you are no longer exporting all members of the class, you may run into an additional problem because of the way that MFC macros work. Several of MFC's helper macros actually declare or define data members. Therefore, these data members must also be exported from your DLL.

For example, the DECLARE_DYNAMIC macro is defined as follows when building an extension DLL:

   #define DECLARE_DYNAMIC(class_name) \
   protected: \
     static CRuntimeClass* PASCAL _GetBaseClass(); \
   public: \
     static AFX_DATA CRuntimeClass class##class_name; \
     virtual CRuntimeClass* GetRuntimeClass() const; \

The line that begins with static AFX_DATA is declaring a static object inside of your class. To export this class correctly and access the run-time information from a client executable, you must export this static object. Because the static object is declared with the modifier AFX_DATA, you only need to define AFX_DATA to be __declspec(dllexport) when building your DLL and define it as __declspec(dllimport) when building your client executable. Because AFX_EXT_CLASS is already defined in this way, you just need to redefine AFX_DATA to be the same as AFX_EXT_CLASS around your class definition.

For example:

   #undef  AFX_DATA
   #define AFX_DATA AFX_EXT_CLASS

   class CExampleView : public CView
   {
      DECLARE_DYNAMIC()
      // ... class definition ...
   };

   #undef  AFX_DATA
   #define AFX_DATA

MFC always uses the AFX_DATA symbol on data items it defines within its macros, so this technique will work for all such scenarios. For example it will work for DECLARE_MESSAGE_MAP.

Note If you are exporting the entire class rather than selected members of the class, static data members are automatically exported.

What do you want to do?

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export C++ functions for use in C-language executables

  • Export C functions for use in C or C++-language executables

  • Determine which exporting method to use

  • Import into an application using __declspec(dllimport)

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • Decorated names

  • Importing and exporting inline functions

  • Mutual imports


Export C++ Functions for Use in C-Language Executables

Home | Overview | How Do I | FAQ | Details | Sample

If you have functions in a DLL written in C++ that you want to access from a C-language module, you should declare these functions with C linkage instead of C++ linkage. Unless otherwise specified, the C++ compiler uses C++ type-safe naming (also known as name decoration) and C++ calling conventions, which can be difficult to call from C.

To specify C linkage, specify extern "C" for your function declarations. For example:

extern "C" __declspec( dllexport ) int MyFunc(long parm1);

What do you want to do?

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Export C functions for use in C or C++-language executables

  • Determine which exporting method to use

  • Import into an application using __declspec(dllimport)

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • Decorated names

  • Linkage specifications


Export C Functions for Use in C or C++ Language Executables

Home | Overview | How Do I | FAQ | Details | Sample

If you have functions in a DLL written in C that you want to access from a C-language or C++-language module, you should use the __cplusplus preprocessor macro to determine which language is being compiled, and then declare these functions with C linkage if being used from a C++-language module. If you use this technique and provide header files for your DLL, these functions can be used by C and C++ users with no change.

The following code shows a header file which can be used by C and C++ client applications:

// MyCFuncs.h
#ifdef __cplusplus
extern "C" {  // only need to export C interface if
              // used by C++ source code
#endif

__declspec( dllimport ) void MyCFunc();
__declspec( dllimport ) void AnotherCFunc();

#ifdef __cplusplus
}
#endif

If you need to link C functions to your C++ executable and the function declaration header files have not used the above technique, in the C++ source file, do the following to prevent the compiler from decorating the C function names:

extern "C" {
#include "MyCHeader.h"
}

What do you want to do?

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Determine which exporting method to use

  • Import into an application using __declspec(dllimport)

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • Decorated names

  • Linkage specifications


Determine Which Exporting Method to Use

Home | Overview | How Do I | FAQ | Details | Sample

To determine which method to use to export functions (a .DEF file or the __declspec(dllexport) keyword), answer the following questions:

  • Will you be continuing to add additional exported functions?

  • Who is using your DLL? For example, is it a third party DLL used by many executables that you cannot rebuild, or is the DLL used only by applications that you can easily rebuild?

Pros and Cons of Using .DEF Files

Exporting functions in a .DEF file gives you control over what the export ordinals are. When you add additional exported functions to your DLL, you can assign them higher ordinal values (higher than any other exported function). When you do this, applications using implicit linking do not have to relink with the new import library that contains the new functions. This is very important, for example, if you are designing a third-party DLL for use by many applications. You can continue to enhance your DLL by adding additional functionality while at the same time ensuring that existing applications will continue to work properly with the new DLL. The MFC DLLs are built using .DEF files.

Another advantage to using a .DEF file is that you can export functions using the NONAME attribute, which places only the ordinal in the exports table in the DLL. For DLLs with a large number of exported functions, using the NONAME attribute can reduce the size of the DLL file. For information about writing a module definition statement, see Rules for Module-Definition Statements. For more information on ordinal export, see Export Functions From a DLL By Ordinal Rather Than By Name.

The major disadvantage of using .a DEF file is that if you are exporting functions in a C++ file, you will either have to place the decorated names in the .DEF file or define your exported functions with standard C linkage by using extern “C” to avoid the name decoration done by the compiler.

If you need to place the decorated names in the .DEF file, you can obtain them by using the tool DUMPBIN or by using the link switch /MAP. Note that the decorated names produced by the compiler are compiler specific. If you place the decorated names produced by the Visual C++ compiler into a .DEF file, applications that link to your DLL must also be built using the same version of Visual C++ so that the decorated names in the calling application match the exported names in the DLL’s .DEF file.

Pros and Cons of Using __declspec(dllexport)

Using __declspec(dllexport) is convenient because you do not have to worry about maintaining a .DEF file and obtaining the decorated names of the exported functions. However, you do not have control over the export ordinals that the compiler generates. This method is suitable if, for example, you are designing a DLL for use with an application that you control; if you rebuild the DLL with new exports, you will also have to rebuild the application.

What do you want to do?

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Export C functions for use in C or C++-language executables

  • Import into an application using __declspec(dllimport)

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • Importing and exporting inline functions.

  • Mutual imports

  • Decorated names


Export Functions from a DLL By Ordinal Rather Than By Name

Home | Overview | How Do I | FAQ | Details | Sample

The simplest way to export functions from your DLL is to export them by name. This is what happens when you use __declspec(dllexport), for instance. But you can instead export functions by ordinal. With this technique, you must use a .DEF file instead of __declspec(dllexport). To specify a function’s ordinal value, append its ordinal to the function name in the .DEF file. For information on specifying ordinals, see Export from a DLL Using .DEF Files.

Tip If you want to optimize your DLL’s file size, use the NONAME attribute on each exported function. With the NONAME attribute, the ordinals are stored in the DLL’s export table rather than the function names. This can be a considerable savings if you are exporting many functions.

What do you want to do?

  • Use a .DEF file so I can export by ordinal

  • Use __declspec(dllexport)


Import into an Application Using __declspec(dllimport)

Home | Overview | How Do I | FAQ | Details | Sample

A program that uses public symbols defined by a DLL is said to import them. When you create header files for applications that use your DLLs to build with, use __declspec(dllimport) on the declarations of the public symbols. The keyword __declspec(dllimport) works whether you export with .DEF files or with the __declspec(dllexport) keyword.

To make your code more readable, define a macro for __declspec(dllimport) and then use the macro to declare each imported symbol:

#define DllImport   __declspec( dllimport )

DllImport int  j;
DllImport void func();

Using __declspec(dllimport) is optional on function declarations, but the compiler produces more efficient code if you use this keyword. However, you must use __declspec(dllimport) in order for the importing executable to access the DLL’s public data symbols and objects. Note that the users of your DLL still need to link with an import library.

You can use the same header file for both the DLL and the client application. To do this, use a special preprocessor symbol which indicates whether you are building the DLL or building the client application. For example:

#ifdef _EXPORTING
   #define CLASS_DECLSPEC    __declspec(dllexport)
#else
   #define CLASS_DECLSPEC    __declspec(dllimport)
#endif

class CLASS_DECLSPEC CExampleA : public CObject
{ ... class definition ... };

What do you want to do?

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Export C functions for use in C or C++-language executables

  • Determine which exporting method to use

  • Prepare the MFC DLL for use by an application, or Prepare the Win32 DLL for use by an application

What do you want to know more about?

  • Using __declspec(dllimport) and __declspec(dllexport)

  • Importing and exporting inline functions

  • Mutual imports


Link an Executable to a DLL

Home | Overview | How Do I | FAQ | Details | Sample

An executable file links to (or loads) a DLL in one of two ways:

  • Implicit linking

  • Explicit linking

Note Implicit linking is sometimes referred to as static load or load-time dynamic linking. Explicit linking is sometimes referred to as dynamic load or run-time dynamic linking.

With implicit linking, the executable using the DLL links to an import library (.LIB file) provided by the maker of the DLL. The operating system loads the DLL when the executable using it is loaded. The client executable calls the DLL’s exported functions just as if the functions were contained within the executable.

With explicit linking, the executable using the DLL must make function calls to explicitly load and unload the DLL, and to access the DLL’s exported functions. The client executable must call the exported functions through a function pointer.

An executable can use the same DLL with either linking method. Furthermore, these mechanisms are not mutually exclusive, as one executable can implicitly link to a DLL and another can attach to it explicitly.

What do you want to do?

  • Link implicitly

  • Link explicitly

  • Determine which linking method to use

What do you want to know more about?

  • Using implicit linking

  • The search path used by Windows to locate a DLL


Link Implicitly

Home | Overview | How Do I | FAQ | Details | Sample

To implicitly link to a DLL, executables must obtain the following from the provider of the DLL:

  • A header file (.H file) containing the declarations of the exported functions and/or C++ classes.

  • An import library (.LIB files) to link with. (The linker creates the import library when the DLL is built.)

  • The actual DLL (.DLL file).

Executables using the DLL must include the header file containing the exported functions (or C++ classes) in each source file that contains calls to the exported functions. From a coding perspective, the function calls to the exported functions are just like any other function call.

To build the calling executable file, you must link with the import library. If you are using an external makefile, specify the file name of the import library where you list other object (.OBJ) files or libraries that you are linking with. If you are working in the Visual C++ development environment, specify the file name of the import library in the Object/Library Modules text box on the Link tab of the Project Settings dialog box.

The operating system must be able to locate the .DLL file when it loads the calling executable.

What do you want to do?

  • Link explicitly

  • Determine which linking method to use

What do you want to know more about?

  • Using implicit linking

  • The search path used by Windows to locate a DLL


Link Explicitly

Home | Overview | How Do I | FAQ | Details | Sample

With explicit linking, applications must make a function call to explicitly load the DLL at run time. To explicitly link to a DLL, an application must:

  • Call LoadLibrary (or a similar function) to load the DLL and obtain a module handle.

  • Call GetProcAddress to obtain a function pointer to each exported function that the application wants to call. Because applications are calling the DLL’s functions through a pointer, the compiler does not generate external references, so there is no need to link with an import library.

  • Call FreeLibrary when done with the DLL.

For example:

typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);
.
.
.
HINSTANCE hDLL;               // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1;    // Function pointer
DWORD dwParam1;
UINT  uParam2, uReturnVal;

hDLL = LoadLibrary("MyDLL");
if (hDLL != NULL)
{
   lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,
                                           "DLLFunc1");
   if (!lpfnDllFunc1)
   {
      // handle the error
      FreeLibrary(hDLL);
      return SOME_ERROR_CODE;
   }
   else
   {
      // call the function
      uReturnVal = lpfnDllFunc1(dwParam1, uParam2);
   }
}

What do you want to do?

  • Link implicitly

  • Determine which linking method to use

What do you want to know more about?

  • LoadLibrary and AfxLoadLibrary

  • GetProcAddress

  • FreeLibrary and AfxFreeLibrary

  • The search path used by Windows to locate a DLL


Determine Which Linking Method to Use

Home | Overview | How Do I | FAQ | Details | Sample

Most applications use implicit linking because it is the easiest linking method to use. However, there are times when explicit linking is necessary. Here are some common reasons to use explicit linking:

  • The application does not know the name of a DLL that it will have to load until run time. For example, the application might need to obtain the name of the DLL and the exported functions from a configuration file.

  • A process using implicit linking is terminated by the operating system if the DLL is not found at process startup. A process using explicit linking is not terminated in this situation and can attempt to recover from the error. For example, the process could notify the user of the error and have the user specify another path to the DLL.

  • A process using implicit linking is also terminated if any of the DLLs it is linked to have a DllMain function that fails. A process using explicit linking is not terminated in this situation.

  • An application that implicitly links to many DLLs can be slow to start because Windows loads all the DLLs when the application loads. To improve startup performance, an application can implicitly link to those DLLs needed immediately after loading and wait to explicitly link to the other DLLs when they are needed.

  • Explicit linking eliminates the need to link the application with an import library. If changes in the DLL cause the export ordinals to change, applications using explicit linking do not have to relink (assuming they are calling GetProcAddress with a name of a function and not with an ordinal value), whereas applications using implicit linking must relink to the new import library.

Here are two hazards of explicit linking to be aware of:

  • If the DLL has a DllMain entry point function, the operating system calls the function in the context of the thread that called LoadLibrary. The entry-point function is not called if the DLL is already attached to the process because of a previous call to LoadLibrary with no corresponding call to the FreeLibrary function. Explicit linking can cause problems if the DLL is using a DllMain function to perform initialization for each thread of a process because threads existing when LoadLibrary (or AfxLoadLibrary) is called will not be initialized.

  • If a DLL declares static-extent data as __declspec(thread), it can cause a protection fault if explicitly linked. After the DLL is loaded with LoadLibrary, it causes a protection fault whenever the code references this data. (Static-extent data includes both global and local static items.) Therefore, when you create a DLL, you should either avoid using thread-local storage, or inform DLL users about potential pitfalls (in case they attempt dynamic loading).

What do you want to do?

  • Link implicitly

  • Link explicitly

What do you want to know more about?

  • Using implicit linking

  • The search path used by Windows to locate a DLL

  • LoadLibrary and AfxLoadLibrary

  • GetProcAddress

  • FreeLibrary and AfxFreeLibrary

  • Using thread local storage in a dynamic-link library (Win32 SDK documentation)


Initialize a DLL

Home | Overview | How Do I | FAQ | Details | Sample

Typically, your DLL has initialization code (such as allocating memory) that must execute when your DLL loads. When using Visual C++, where you add code to initialize your DLL depends on the kind of DLL you are building. If you don’t need to add initialization or termination code, there’s nothing special you have to do when building your DLL. If you need to initialize your DLL, the following table describes where to add your code.

Kind of DLL | Where to add initialization and termination code
Regular DLL | In the DLL’s CWinApp object’s InitInstance and ExitInstance.
Extension DLL | In the DllMain function generated by AppWizard.
Non-MFC DLL | In a function called DllMain that you provide.

In Win32, all DLLs may contain an optional entry-point function (usually called DllMain) that is called for both initialization and termination. This gives you an opportunity to allocate or release additional resources as needed. Windows calls the entry-point function in four situations: process attach, process detach, thread attach, and thread detach.

The C run-time library provides an entry-point function called _DllMainCRTStartup, and it calls DllMain. Depending on the kind of DLL, either you should have a function called DllMain in your source code or you should use the DllMain provided in the MFC library.

What do you want to do?

  • Initialize regular DLLs

  • Initialize extension DLLs

  • Initialize non-MFC DLLs

What do you want to know more about?

  • The C run-time library behavior and _DllMainCRTStartup

  • The function specification for DllMain (Win32 SDK documentation)

  • Dynamic-link library entry-point function (Win32 SDK documentation)


Initialize Regular DLLs

Home | Overview | How Do I | FAQ | Details | Sample

Because regular DLLs have a CWinApp object, they should perform their initialization and termination tasks in the same location as an MFC application: in the InitInstance and ExitInstance member functions of the DLL’s CWinApp-derived class. Because MFC provides a DllMain function that is called by _DllMainCRTStartup for PROCESS_ATTACH and PROCESS_DETACH, you should not write your own DllMain function. The MFC-provided DllMain function calls InitInstance when your DLL is loaded and it calls ExitInstance before the DLL is unloaded.

A regular DLL can keep track of multiple threads by calling TlsAlloc and TlsGetValue in its InitInstance function. These functions allow the DLL to track thread-specific data.

In your regular DLL that dynamically links to MFC, if you are using any MFC OLE, MFC Database (or DAO), or MFC Sockets support, respectively, the MFC debug extension DLLs MFCOxxD.DLL, MFCDxxD.DLL, and MFCNxxD.DLL (where xx is the version number) are linked in automatically. You must call one of the following predefined initialization functions for each of these DLLs that you are using in your regular DLL's CWinApp::InitInstance.

Type of MFC Support | Initialization Function to Call
MFC OLE (MFCOxxD.DLL) | AfxOleInitModule
MFC Database (MFCDxxD.DLL) | AfxDbInitModule
MFC Sockets (MFCNxxD.DLL) | AfxNetInitModule

What do you want to do?

  • Initialize extension DLLs

  • Initialize non-MFC DLLs

What do you want to know more about?

  • The C run-time library behavior and _DllMainCRTStartup

  • Using extension DLL, Database/OLE/Sockets in regular DLL

  • Processes and threads (Win32 SDK documentation)

  • Thread local storage wrappers (MFC Technical Note 58)


Initialize Extension DLLs

Home | Overview | How Do I | FAQ | Details | Sample

Because extension DLLs do not have a CWinApp-derived object (as do regular DLLs), you should add your initialization and termination code to the DllMain function that AppWizard generates.

AppWizard provides the following code for extension DLLs. In the code below, PROJNAME is a placeholder for the name of your project.

#include "stdafx.h"
#include <afxdllx.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
static AFX_EXTENSION_MODULE PROJNAMEDLL = { NULL, NULL };

extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
   if (dwReason == DLL_PROCESS_ATTACH)
   {
      TRACE0("PROJNAME.DLL Initializing!\n");

      // Extension DLL one-time initialization
      AfxInitExtensionModule(PROJNAMEDLL,
                                 hInstance);

      // Insert this DLL into the resource chain
      new CDynLinkLibrary(Dll3DLL);
   }
   else if (dwReason == DLL_PROCESS_DETACH)
   {
      TRACE0("PROJNAME.DLL Terminating!\n");
   }
   return 1;   // ok
}

Creating a new CDynLinkLibrary object during initialization allows the extension DLL to export CRuntimeClass objects or resources to the client application.

If you are going to use your extension DLL from one or more regular DLLs, you must export an initialization function that creates a CDynLinkLibrary object. That function must be called from each of the regular DLLs that use the extension DLL. An appropriate place to call this initialization function is in the InitInstance member function of the regular DLL’s CWinApp-derived object before using any of the extension DLL's exported classes or functions.

In the DllMain that AppWizard generates, the call to AfxInitExtensionModule captures the module’s run-time classes (CRuntimeClass structures) as well as its object factories (COleObjectFactory objects) for use when the CDynLinkLibrary object is created. You should check the return value of AfxInitExtensionModule; if a zero value is returned from AfxInitExtensionModule, return zero from your DllMain function.

If your extension DLL will be explicitly linked to an executable (meaning the executable calls AfxLoadLibrary to link to the DLL), you should add a call to AfxTermExtensionModule on DLL_PROCESS_DETACH. This function allows MFC to clean up the extension DLL when each process detaches from the extension DLL (which happens when the process exits, or when the DLL is unloaded as a result of a AfxFreeLibrary call). If your extension DLL will be linked implicitly to the application, the call to AfxTermExtensionModule is not necessary.

Applications that explicitly link to extension DLLs must call AfxTermExtensionModule when freeing the DLL. They should also use AfxLoadLibrary and AfxFreeLibrary (instead of the Win32 functions LoadLibrary and FreeLibrary) if the application uses multiple threads. Using AfxLoadLibrary and AfxFreeLibrary ensures that the startup and shutdown code that executes when the extension DLL is loaded and unloaded does not corrupt the global MFC state.

Because the MFCx0.DLL is fully initialized by the time DllMain is called, you can allocate memory and call MFC functions within DllMain (unlike the 16-bit version of MFC).

Extension DLLs can take care of multithreading by handling the DLL_THREAD_ATTACH and DLL_THREAD_DETACH cases in the DllMain function. These cases are passed to DllMain when threads attach and detach from the DLL. Calling TlsAlloc when a DLL is attaching allows the DLL to maintain thread local storage (TLS) indexes for every thread attached to the DLL.

Note that the header file AFXDLLX.H contains special definitions for structures used in extension DLLs, such as the definition for AFX_EXTENSION_MODULE and CDynLinkLibrary. You should include this header file in your extension DLL.

Note It is important that you neither define nor undefine any of the _AFX_NO_XXX macros in stdafx.h. See the Knowledge Base article "PRB: Problems Occur When Defining _AFX_NO_XXX." You can find Knowledge Base articles on the MSDN Library CD, or at http://www.microsoft.com/kb/.

A sample initialization function that handles multithreading is included in Using Thread Local Storage in a Dynamic-Link Library in the Win32 SDK documentation. Note that the sample contains an entry-point function called LibMain, but you should name this function DllMain so that it works with the MFC and C run-time libraries.

The MFC sample DLLHUSK demonstrates the use of initialization functions.

What do you want to do?

  • Initialize regular DLLs

  • Initialize non-MFC DLLs

What do you need to know more about?

  • The C run-time library behavior and _DllMainCRTStartup

  • Using extension DLL, Database/OLE/Sockets in regular DLL

  • The function specification for DllMain (Win32 SDK documentation)

  • Dynamic-link library entry-point function (Win32 SDK documentation)


Initialize Non-MFC DLLs

Home | Overview | How Do I | FAQ | Details | Sample

To initialize non-MFC DLLs, your DLL source code must contain a function called DllMain. The following code presents a basic skeleton showing what the definition of DllMain might look like:

BOOL APIENTRY DllMain(HANDLE hModule,
                      DWORD  ul_reason_for_call,
                      LPVOID lpReserved)
{
    switch( ul_reason_for_call ) {
    case DLL_PROCESS_ATTACH:
    .
    .
    .
    case DLL_THREAD_ATTACH:
    .
    .
    .
    case DLL_THREAD_DETACH:
    .
    .
    .
    case DLL_PROCESS_DETACH:
    .
    .
    .
    }
    return TRUE;
}

Note The Win32 SDK documentation for DllEntryPoint says that the actual name of the entry-point function must be specified on the linker command line with the /ENTRY switch. With Visual C++, you do not need to use the /ENTRY switch if the name of your entry-point function is DllMain. In fact, if you do use the /ENTRY switch and name your entry-point function something other than DllMain, the C run-time library will not get initialized properly.

What do you want to know more about?

  • The function specification for DllMain (Win32 SDK documentation)

  • Dynamic-link library entry-point function (Win32 SDK documentation)

  • The C run-time library behavior and _DllMainCRTStartup


Create a Resource-Only DLL

Home | Overview | How Do I | FAQ | Details | Sample

A resource-only DLL is a DLL that contains nothing but resources, such as icons, bitmaps, strings, and dialog boxes. Using a resource-only DLL is a good way to share the same set of resources among multiple programs.

To create a resource-only DLL, you create a new Win32 DLL (non-MFC) project and add your resources to the project.

  • Click New on the File menu and click the Projects tab. Choose Win32 Dynamic-Link Library as your target type.

  • Create a new resource script that contains the resources (such as a string or a menu) for the DLL and save the .RC file.

  • On the Project menu, select Add To Project then click Files. Use the Insert Files into Project dialog box to insert the new .RC file into the project.

  • On the Project Menu, select Settings. Select the Link tab of the Project Settings dialog, then in the Project Options box, add the /NOENTRY option. /NOENTRY prevents the linker from linking a reference to _main into the DLL; this option is required to create a resource-only DLL.

  • Build the DLL.

The application that uses the resource-only DLL should call LoadLibrary to explicitly link to the DLL. To access the resources, call the generic functions FindResource and LoadResource, which work on any kind of resource, or call one of the following resource-specific functions:

  • FormatMessage

  • LoadAccelerators

  • LoadBitmap

  • LoadCursor

  • LoadIcon

  • LoadMenu

  • LoadString

The application should call FreeLibrary when it is finished using the resources.

What do you want to know more about?

  • Working with resources


DLL Sample Programs

Home | Overview | How Do I | FAQ | Details

Two MFC Advanced Concepts samples dealing with DLLs are included with Visual C++:

DLLHUSK Demonstrates how to write, build, and use extension DLLs.

DLLTRACE Demonstrates how to write, build, and use regular DLLs.

Examining the source code and makefiles for these samples may help you in building your DLLs.


Exception Handling Tasks

Home | Overview | FAQ | Details

When exceptional conditions occur in your program, be ready for them by supplying exception handlers. Visual C++ supplies three different mechanisms for handling exceptions. For guidance on which exception handling mechanism to use, see the overview.

The following categories of tasks are listed in this topic:

  • General Exception Tasks

  • MFC Exception Tasks

  • C++ Exception Tasks

  • Structured Exception Handling Tasks

What do you want to do?

General Exception Tasks

  • Learn what exception handling is

  • Learn what exception handling mechanisms are available

  • Learn which mechanism to use when

MFC Exception Tasks

  • Handle an exception: in MFC, in C++ without MFC, in C under Windows NT or Windows 95

  • Convert my program from MFC exception macros to C++ exceptions

  • Examine the contents of an MFC exception object

  • Free objects correctly when handling an exception

  • Throw an exception from my own function

  • Learn what to do with exceptions that occur in a constructor

  • Handle exceptions in an MFC database program

  • Handle exceptions in an MFC OLE program

C++ Exception Tasks

Note These tasks apply also to MFC.

  • Handle exceptions in a type-safe manner

  • Learn about what happens to unhandled exceptions

  • Understand the overhead for using exception handling

Structured Exception Handling Tasks

  • Learn about Windows NT exception and termination handlers

  • Learn to write exception handlers with structured exception handling

  • Learn to write termination handlers with structured exception handling


File-Handling Tasks

Home | Overview | Details

In addition to run-time library file-handling routines and Win32 API file-handling routines, Visual C++ supplies MFC class CFile and several derived classes, such as CStdioFile for text files. Use CFile in your MFC programs.

For more information about alternatives to MFC file handling, see File Handling in the Run-Time Library Reference and File I/O in the Platform SDK.

For information about derived CFile classes, see the MFC hierarchy chart.

What do you want to do?

Use CFile

  • Open a file with CFile

  • Read and write a file with CFile

  • Close a file with CFile

  • Access file status with CFile

Use MFC Serialization (Object Persistence)

  • Create a serializable class

  • Serialize an object via a CArchive object

  • Create a CArchive object

  • Use CArchive << and >> operators

  • Store and load CObjects and CObject-derived objects via an archive

See Also CArchive, CObject


Internet Tasks

Home | Overview | FAQ | Details | Sample

The tasks listed in this topic cover the use of Internet Server API (ISAPI) extension DLLs, ISAPI filters, and parse maps.

The following categories of tasks are listed in this topic:

  • ActiveX Controls, Documents and Asynchronous Moniker Tasks

  • Internet Server Application (ISA) Tasks

  • ISAPI Filter Tasks

  • ISAPI Parse Map Tasks

  • Other ISAPI Tasks

  • WinInet Tasks

What do you want to do?

ActiveX Controls, Documents and Asynchronous Moniker Tasks

  • Learn about ActiveX controls

  • Learn about Active documents

  • Learn about Asynchronous Monikers

  • Learn about ActiveX controls in the Internet context

  • Learn about Active documents in the Internet context

  • Optimize an ActiveX control

  • Creating Signed CAB Files for MFC and ATL Controls

Internet Server Application (ISA) Tasks

  • Write an ISA

ISAPI Filter Tasks

  • Filter incoming or outgoing data for an Internet Server

  • Register an ISAPI filter application for desired events

  • Process ISAPI filter notifications

ISAPI Parse Map Tasks

  • Create a parse map for an ISAPI extension

  • Use a parse map with ISAPI forms

  • Declare a command in a parse map

  • Pass a string from the Universal Resource Locator (URL)

  • Use named parameters in a parse map

  • Manage parse map parameters

Other ISAPI Tasks

  • Learn about ISAPI server extensions

  • Create an ISAPI server filter

  • Create an ISAPI server extension

  • Learn about ISAPI and databases

  • Learn about ISAPI debugging

  • Get some ISAPI programming tips

WinInet Tasks

  • Learn about WinInet, the Win32 API functions for Internet access

  • Review what's involved with WinInet programming

  • Write an Internet client application, using MFC WinInet classes

  • Write an FTP client application

  • Write an HTTP client application

  • Write a Gopher client application


Internet Sample List

Home | Overview | How Do I

Visual C++ includes these Internet client sample programs:

  • FTPTREE A dialog-based application that displays the contents of an FTP site in a tree control.

  • TEAR Shows how to write an MFC console application that uses WININET.DLL to communicate with the Internet. This sample shows how to form an HTTP request using CHttpFile against CHttpConnection and CInternetSession objects.

Visual C++ includes these Internet server sample programs. The first three samples use the MFC ISAPI classes:

  • MFCUCASE Demonstrates an ISAPI filter that uses the filter functions OnSendRawData and OnUrlMap to convert strings to uppercase.

  • WWWQUOTE Demonstrates an ISAPI server extension DLL that uses an SQL Server database. The sample shows proper use of the parse map macros, the CHttpServer class, and thread-safe programming techniques.

  • COUNTER Demonstrates using an ISAPI server extension DLL to send image data (rather than HTML data) back to a Web browser.

  • HTTPSVR Demonstrates the use of MFC and its Windows Sockets (WinSock) classes in implementing a simple World Wide Web HTTP server.

Back to Internet Tasks


Mail-Enabling Tasks (MAPI)

Home | Overview | Details | Sample

Use MFC's implementation of simple MAPI to allow your users to send their documents via e-mail.

For more information about the Windows Messaging API (MAPI), see "Concepts and Architecture" in the MAPI Programmer's Guide.

What do you want to do?

  • Implement a Send Mail command with MFC


MAPI Sample List

Home | Overview | How Do I | Details

See the following sample programs that illustrate Microsoft Messaging API (MAPI) functionality:

  • NPP

  • DRAWCLI

Back to Mail-Enabling Tasks (MAPI)


Memory-Management Tasks

Home | Overview | Details

The following tasks deal with the C++ memory-management techniques that you should use in MFC.

For non-MFC information about memory management in programs for Windows, see Memory Management in the Win32 Programmer's Reference.

What do you want to do?

General Memory-Management Techniques

  • Allocate memory on the stack frame in MFC

  • Allocate memory on the heap in MFC

  • Allocate a resizable memory block in MFC

Allocating Memory for Specific Data Structures

  • Allocate memory for an array of bytes in MFC

  • Deallocate memory for an array correctly

  • Allocate memory for a data structure in MFC

  • Allocate memory for an object in MFC


Message-Mapping Tasks

Home | Overview | Details | Tutorial

Use MFC message mapping to connect specific Windows messages to handler functions. You can specify which object in your program handles a message (although some objects, such as documents, can handle only command messages, not window messages). ClassWizard and WizardBar help you map messages easily.

For general information about messages and message queues in Windows, see Messages and Message Queues in the Win32 Programmer's Reference.

What do you want to do?

  • Map messages

  • Override MFC's standard command routing

  • Declare message handler functions

  • Map a range of messages to a single message handler

  • Map a range of command IDs to a single command handler

  • Map a range of control IDs to a single message handler

  • Create an update handler for a menu item or toolbar button


MFC Tasks

Home | Overview | Details | Sample | Tutorial

Use the following lists as a guide to finding how-to information about the Microsoft Foundation Class Library (MFC).

What do you want to do?

General MFC Tasks

  • Build on the MFC framework

  • Interpret standard comments in MFC source files

  • Manage the state data of MFC modules

  • Manage memory in MFC

  • Perform background processing in an MFC application

Other MFC Tasks, By Category

  • ActiveX Control Tasks

  • CArchive Tasks

  • Clipboard Tasks

  • CObject Tasks

  • Control Tasks

  • Control-Bar Tasks

  • Collection Class Tasks

  • ClassWizard, WizardBar, and ClassView Tasks

  • Database Tasks

  • Date and Time Tasks

  • Dialog-Bar Tasks

  • Dialog-Box Tasks

  • Document/View Tasks

  • File-Handling Tasks

  • Help Tasks: Context-Sensitive Help for Your Programs

  • Internet Tasks

  • Mail-Enabling Tasks (MAPI)

  • Memory-Management Tasks

  • Menu Tasks

  • Message-Mapping Tasks

  • Multithreading Tasks

  • OLE Tasks

  • Printing and Print Preview Tasks

  • Serialization Tasks

  • State Data Tasks (MFC module states)

  • Status-Bar Tasks

  • String Tasks

  • Toolbar Tasks

  • Window Tasks

  • Windows Sockets Tasks


Mixed-Language Programming Tasks

Home | Overview | Details

Mixed-language programming involves building a program from modules written in two or more different languages.

What do you want to do?

  • Learn more about mixed-language programming issues

  • Make C calls to Fortran

  • Make Fortran calls to C

  • Build a mixed-language program

  • Use C++ in mixed-language programs

  • Handle data types in multiple languages


Multibyte Character Set (MBCS) Tasks

Home | Overview | Details

For international portability, code your program with Unicode or multibyte character sets (MBCS).

What do you want to do?

  • Enable MBCS in my program

  • Enable both Unicode and MBCS in my program

  • Use MBCS to create an internationalized program

  • See a summary of MBCS programming

  • Learn about the Input Method Editor (IME)

  • Learn about generic-text mappings for byte-width portability


Multithreading Tasks

Home | Overview | Details | Sample

Multiple threads of execution allow you to perform tasks concurrently in your program.

For information about multithreading without MFC, see Multithreading with C and Win32.

What do you want to do?

Creating and Using Multiple Threads of Execution

  • Create multiple threads in C and Win32

  • Create a user-interface thread in MFC

  • Create a worker thread in MFC

  • Design a thread-safe class

  • Terminate a thread

  • Retrieve the exit code of a thread

Synchronizing Threads

  • Use the MFC thread synchronization classes

Communicating Among Multiple Threads

  • Access objects from multiple threads

  • Access MFC objects from non-MFC threads

  • Use Windows handles across threads

  • Communicate between threads

See Also CWinThread, CSyncObject, CSemaphore, CMutex, CCriticalSection, CEvent, CMultiLock, CSingleLock


Multithreading Sample List

Home | Overview | How Do I | Details | Sample

See the following sample programs that illustrate multithreaded programming:

  • MTGDI

  • MTMDI

  • MTRECALC

  • MUTEXES

Back to Multithreading Tasks


OLE Tasks

Home | Overview | Details | Sample | Tutorial

This article family details tasks for OLE in-place activation or visual editing, OLE containers and servers, and OLE uniform data transfer (UDT) and drag and drop. For information about ActiveX controls (formerly known as OLE controls), see ActiveX Control Tasks. For information about Automation (formerly OLE Automation), see Automation Tasks.

For more information about OLE without MFC, see Overview in the OLE Programmer's Reference.

The following categories of tasks are listed in following topics:

  • OLE Visual Editing (In-Place Activation) Tasks

  • OLE Container and Server Tasks

  • OLE Drag and Drop and Clipboard Tasks

  • OLE Tracker Tasks

  • OLE Date and Time Tasks

  • MFC State Data Tasks

See Also Connection Point Tasks, Automation Tasks


OLE Visual Editing (In-Place Activation) Tasks

Home | Overview | Details | Sample | Tutorial

Visual editing, also called in-place activation, lets users edit linked or embedded items, such as Excel spreadsheets, right in a document, such as a Word for Windows document.

What do you want to do?

  • Create an OLE visual editing application (see Activation)

  • Manage menus in an OLE visual editing container application

  • Manage menus in an OLE visual editing server application

  • Merge menus for OLE visual editing and in-place activation


OLE Container and Server Tasks

Home | Overview | Details | Sample | Tutorial

OLE containers contain "items" linked or embedded from other applications. OLE servers supply items that can be linked or embedded in other applications.

What do you want to do?

  • Implement a container application

  • Implement a COM component (server) application

  • Create an COM component (container/server) application

  • Link to embedded objects in a COM component (container/server)

  • Implement COM component (server) documents

  • Implement in-place frame windows

  • Implement COM component (server) items

  • Work with COM container (client) items

  • Handle COM client-item notifications

  • Use the compound files format for your data

  • Cause your COM component (server) to register itself


OLE Drag and Drop and Clipboard Tasks

Home | Overview | Details | Sample | Tutorial

OLE drag and drop allows users to drag data items between applications or between windows in a single application. Any data that could be placed on the clipboard can be dragged and dropped.

What do you want to do?

  • Implement an OLE drop source

  • Implement an OLE drop target

  • Create OLE data objects

  • Destroy OLE data objects

  • Create OLE data sources

  • Destroy OLE data sources

  • Insert data into an OLE data source

  • Determine available formats in an OLE data object

  • Retrieve data from an OLE data object

  • Use the clipboard with OLE

  • Copy data to the clipboard (OLE)

  • Paste data from the clipboard (OLE)

  • Add clipboard formats (OLE)


OLE Tracker Tasks

Home | Overview | Details | Sample | Tutorial

OLE tracker objects let you place visible markers around linked or embedded items when they are selected.

What do you want to do?

  • Implement OLE trackers

  • Use rubber-banding with OLE trackers


OLE Date and Time Tasks

Home | Overview | Details | Sample | Tutorial

MFC supplies several classes derived from the VARIANT data type for manipulating date and time data in Automation.

What do you want to do?

  • Get the current time with COleDateTime

  • Calculate elapsed time with COleDateTimeSpan

  • Format a string representation of a time or elapsed time (OLE)

See Also COleDateTime, COleDateTimeSpan


MFC State Data Tasks

Home | Overview | Details | Sample | Tutorial

MFC manages the state of its objects when the flow of execution enters and leaves a module and allows you to switch module states with macros. This is an advanced topic.

What do you want to do?

  • Manage the state data of MFC modules


OLE Sample List

Home | Overview | How Do I | Details | Tutorial

See the following sample programs that illustrate OLE functionality:

OLE Tutorial Samples

  • AUTOCLIK

  • AUTODRIV

  • CONTAINER

OLE Containers and Servers (Visual Editing)

  • CONTAINER

  • HIERSVR

  • INPROC

  • OCLIENT

  • SUPERPAD

  • WORDPAD

OLE Drag and Drop and Clipboard Support

  • HIERSVR

Office Binder

  • BINDSCRB

Windows 95 Logo Compliance

  • DRAWCLI

OLE Object Viewer

  • OLEVIEW

Back to OLE Tasks.

Back to OLE in MFC: Overview.

See Also Automation Sample List


OLE Tutorial List

Home | Overview | How Do I | Details | Sample

See the following tutorials on OLE:

  • SCRIB7 - Adding OLE Server Support to Scribble

  • OLE Container Tutorial

Back to OLE Tasks.

Back to OLE in MFC: Overview.

See Also ActiveX Control Tutorial, Automation Server Tutorial


Reusing Code Tasks

Home | Overview | Details

The following tasks involve reusing code with the aid of the Gallery.

You can enhance your projects by using items from the Gallery. The items can be prepackaged items such as the Visual C++ Components and Registered ActiveX Controls, or code you have created and added to the Gallery. You can also add third-party components and controls.

What do you want to do?

  • Access and view Gallery contents

  • Add a Gallery item to a project

  • Add items to the Gallery

  • Organize Gallery items

  • Learn about Registered ActiveX Controls

  • Learn about Visual C++ Components


Serialization Tasks

Home | Overview | Details

The following tasks involve serializing (that is, reading or writing in serial order) MFC documents and their data to persistent storage. This storage might be a file or some other medium, such as an in-memory file. The data in a document might consist of simple data types, such as integers; of embedded C++ objects; of pointers to C++ objects; or of all three kinds of data.

For a discussion of why MFC supplies a serialization mechanism, see Serialization: Overview and CArchive Tasks.

What do you want to do?

  • Create a serializable class

  • Serialize an object via a CArchive object

  • Create a CArchive object

  • Use CArchive << and >> operators

  • Store and load CObjects via an archive

See Also CArchive, CObject


String Handling Tasks

Home | Overview | Details

Use MFC class CString rather than the run-time library string functions in most of your MFC programming.

For related information about working with strings, see String Manipulation in the Run-Time Library Reference and String Manipulation in the Win32 Programmer's Reference.

The following categories of tasks are listed in this topic:

  • Basic CString Tasks

  • CString Operations Relating to C-Style Strings

  • CString Argument Passing

  • Unicode and Multibyte Character Set (MBCS) Support in CString

  • CString Exception Cleanup

What do you want to do?

Basic CString Tasks

  • Use CString objects

  • Create a CString from a standard C literal string

  • Access individual characters in a CString

  • Concatenate two CString objects

  • Compare CString objects

  • Enable or disable CString reference counting

CString Operations Relating to C-Style Strings

  • Convert a CString to a C-style null-terminated string

  • Convert between CString and const char pointers

  • Use CString member functions in place of standard run-time functions

  • Modify CString contents directly

  • Use CString objects with variable argument functions

  • Use CString formal parameters correctly

CString Argument Passing

  • Pass CString function arguments

  • Return a CString object from a function

Unicode and Multibyte Character Set (MBCS) Support in CString

  • Use Unicode/MBCS in CString

CString Exception Cleanup

  • Clean up CString objects after an exception


Template Tasks

Home | Overview | Details

Use C++ templates to create type-safe functions and classes, especially when you need essentially the same function or class to deal with multiple types of data.

What do you want to do?

  • Learn more about templates

  • Learn when to use templates

  • Use function templates

  • Use class templates

  • Understand the C++ syntax for templates

  • Use a template instead of a C macro

  • Use a template instead of a void pointer

  • Use templates to create collection classes

  • Learn more about the template-based MFC collection classes

  • Use templates to create smart pointers

See Also Active Template Library (ATL)


Unicode Programming Tasks

Home | Overview | Details | Sample

Unicode and multibyte character sets (MBCS) are two implementations of "wide characters," that is, characters two bytes wide rather than one byte wide.

For related information on both, see International Programming Topics. The tasks below are for Unicode, which is available on Windows NT but not on Windows 95.

What do you want to do?

  • Install Unicode support via MFC

  • Enable Unicode in my program

  • Enable both Unicode and MBCS in my program

  • Use Unicode to create an internationalized program

  • Learn the benefits of Unicode, including how using Unicode makes my program more efficient on Windows NT

  • Use wmain so I can pass wide-character arguments to my program

  • See a summary of Unicode programming

  • Learn about generic-text mappings for byte-width portability


Win32 Programming Tasks

Home | Overview | Details

For most task-oriented information about general programming for Windows (as opposed to MFC programming for Windows), see the Win32 SDK documentation. The article Win32 Topics in this documentation contains links to many of the most important programming topics in the Win32 SDK documentation.

A few tasks are covered here instead.

What do you want to do?

  • Understand the WINDOWS.H include file

  • Use STRICT type checking


Windows Sockets Tasks

Home | Overview | Details | Sample

Use Windows Sockets for network programming. Use sockets to send or receive data over a network. MFC supports sockets with two classes.

For information about Windows Sockets without MFC, see Windows Sockets in the Win32 Programmer's Reference.

What do you want to do?

Basic Sockets

  • Find out what Windows Sockets is

  • Use Windows sockets with MFC archive objects

  • Set up communication between a server socket and a client socket

  • Derive from an MFC Windows sockets class

  • Handle Windows sockets notifications in MFC

Advanced Sockets

  • Use class CAsyncSocket for Windows sockets flexibility

  • Create a CAsyncSocket object

  • Manage blocking in a CAsyncSocket object

  • Manage byte-order issues in a CAsyncSocket object

  • Convert byte orders in an MFC Windows socket

  • Convert strings in MFC Windows sockets

See Also CAsyncSocket, CSocket, CArchive


Windows Sockets Sample List

Home | Overview | Details

See the following sample programs that illustrate Windows Sockets functionality:

  • CHATTER

  • CHATSRVR

Back to Windows Sockets Tasks


Working with Classes Tasks

Home | Overview | Details

ClassView, ClassWizard, and WizardBar are tools designed to make it easy to update or add to classes in your project workspace. Such tasks include creating new classes, adding new member functions and variables, mapping messages to member functions, defining Windows message handlers, overriding MFC virtual functions, and adding Automation methods and properties. These tools also let you easily navigate or browse through the class structure.

What do you want to know more about?

  • Get an overview of ClassView or details on ClassView

  • Get an overview of WizardBar or details on WizardBar

  • Get an overview of ClassWizard or details on ClassWizard

  • Get an overview of MFC or details on MFC

What do you want to do?

  • Add a class to a project

  • Add member functions to the selected class

  • Add member variables to the selected class

  • Override a virtual function

  • Go to the definition of the class or member

  • Go to the references to the class or member

  • Display derived class or base class graphs

  • Reuse a class by storing it in the Gallery for later use in other projects

  • Set a breakpoint on a member function

  • Navigate through code

  • Create a DAO or ODBC recordset class and its associated data sources, tables, and columns

  • Create a database form view (record view) associated with a recordset (for DAO or ODBC)

  • Update a handler function to update the state of any user-interface objects (menus, toolbar buttons) associated with a command ID

  • Filter the messages available for mapping in a class

  • Add Automation properties and methods to a class

  • Add properties to an ActiveX control

  • Add methods to an ActiveX control

  • Create a handler function for an ActiveX control event

  • Interpret the special comment sections that ClassWizard writes into code

Importing and Selecting Classes

  • Create a class from a type library

  • Import the elements of a type library

Mapping Messages Tasks

  • Map messages to functions

  • Define a message handler function for a button in a dialog box

  • Define a member variable of your class for a control in a dialog box

  • Delete a message handler

  • Edit a message handler

  • Define a message handler function for a reflected message

  • Declare a variable based on a new control class

Dialog Data Exchange and Validation (DDX and DDV) Tasks

  • Use dialog data exchange to move data between a dialog box and the class that represents it (either direction)

  • Define a member variable to represent a dialog-box control (for DDX)

  • Initialize a member variable representing a dialog-box control (for DDX)

  • Use dialog data validation to validate user entries in dialog-box controls

  • Customize dialog data exchange and validation

ClassWizard Update Tasks

  • Keep ClassWizard updated when code changes

  • Delete a class

  • Rename or move a class

  • Rebuild the ClassWizard (.CLW) file

ClassWizard Database Tasks

  • Create a recordset class

  • Bind the fields in a recordset to columns in a database table

  • Create a database form (e.g. for data entry or record viewing)

  • Map the controls on a form to recordset fields

ClassWizard Automation Tasks

  • Add Automation properties

  • Add Automation methods

  • Access Automation servers


Frequently Asked Questions: Adding Program Functionality

Home | Overview | How Do I | Details

Note If you don’t see a category below that fits your question, try the closest categories. If you are unsuccessful, it means that Visual C++ doesn’t currently supply an FAQ topic for your question. However, the answer you seek still might be available. Try searching for keywords.

Frequently asked questions in this documentation, by category:

  • CObject Class

  • Databases

  • DLLs

  • Exception Handling

  • Internet Programming


Class CObject: Frequently Asked Questions

Home | Overview | How Do I | Details

This section covers questions on class CObject.

What do you want to know more about?

  • Do I have to derive new classes from CObject?

  • What does it cost me to derive a class from CObject?


Do I have to derive new classes from CObject?

Home | Overview | How Do I | FAQ

No, you don't.

Derive a class from CObject when you need the facilities it provides, such as serialization or dynamic creatability. Many data classes need to be serialized to files, so it's often a good idea to derive them from CObject. For an example of a class derived from CObject, see The Document's Data: Class CStroke in the Scribble tutorial.


What does it cost me to derive a class from CObject?

Home | Overview | How Do I | FAQ

The overhead in deriving from class CObject is minimal. Your derived class inherits only four virtual functions and a single CRuntimeClass object.


Databases: Frequently Asked Questions

Home | Overview | How Do I | Details | ODBC Driver List

This topic covers frequently asked questions about both DAO and ODBC.

Your question might be one of those listed here.

What do you want to know more about?

  • What data sources can I access with DAO and ODBC?

  • Can I call DAO or ODBC APIs directly from my MFC database program?


What Data Sources Can I Access with DAO and ODBC?

Home | Overview | How Do I | FAQ

Both sets of MFC classes let you access a wide variety of data sources and make it possible to write applications that are independent of the data source.

Databases You Can Access with DAO

Using DAO and the MFC DAO classes, you can access the following sources of data:

  • Databases using the Microsoft Jet database engine, created with Microsoft Access or Microsoft Visual Basic, versions 1.x, 2.x, and 3.0 of the database engine

  • Installable ISAM databases, including:
    • Microsoft FoxPro, versions 2.0, 2.5, and 2.6. Can import/export data to and from version 3.0, but can’t create objects

    • dBASE III, dBASE IV, and dBASE 5.0

    • Paradox, versions 3.x, 4.x, and 5.x
  • Open Database Connectivity (ODBC) databases, including but not limited to Microsoft SQL Server, SYBASE® SQL Server, and ORACLE® Server. To access an ODBC database, you must have an appropriate ODBC driver for the database you wish to access. See the article ODBC Driver List for a list of ODBC drivers included in this version of Visual C++ and for information about obtaining additional drivers.

  • Microsoft Excel, versions 3.0, 4.0, 5.0, and 7.0 worksheets

  • Lotus WKS, WK1, WK3, and WK4 spreadsheets

  • Text files

DAO is best used with databases that the Microsoft Jet database engine can read. That includes all of the above except ODBC data sources. Best performance is with Microsoft Jet (.MDB) databases. Attaching external tables, especially in ODBC data sources, to an .MDB database is more efficient than opening the external database directly via the MFC DAO classes without attaching. For more information on external data sources, see the article DAO External: Working with External Data Sources.

Databases You Can Access with ODBC

Using ODBC and the MFC ODBC classes, you can access any data source, local or remote, for which the user of your application has an ODBC driver. Both 16-bit and 32-bit ODBC drivers are available for a wide range of data sources. If you're working with a Microsoft Jet (.MDB) database, it's more efficient to use the DAO classes than the Microsoft Access ODBC driver.


Can I Call DAO or ODBC Directly?

Home | Overview | How Do I | FAQ

As usual in MFC, if you need finer control, you can call DAO or ODBC directly in addition to accessing them through the classes. MFC attempts to simplify programming for Windows, but it also stays out of your way if you need access to the underlying APIs.


DLLs: Frequently Asked Questions

Home | Overview | How Do I | Details | Sample

Following are some frequently asked questions (FAQ) about DLLs.

  1. How do I port my 16-bit DLL to a Win32 DLL?

  2. How do I convert my USRDLL to a regular DLL that uses the MFC shared library?

  3. How do I export data from a DLL?

  4. How do I share data in my DLL with an application or with other DLLs?

  5. Can a multithreaded application access an MFC DLL in different threads?

  6. Can an MFC DLL create multiple threads?

  7. Are there any MFC classes or functions that cannot be used in an MFC DLL?

  8. How do I debug my DLL?

  9. What optimization techniques should I use to improve the client application’s performance when loading?

  10. There’s a memory leak in my regular DLL, but my code looks fine. How can I find the memory leak?

  11. How do I create a modal dialog box from within a regular DLL?


How do I port my 16-bit DLL to a Win32 DLL?

Home | Overview | How Do I | FAQ | Details | Sample

If you have built 16-bit DLLs for Windows 3.x, you should find that building 32-bit DLLs for Windows 95 and Windows NT is more convenient. Visual C++ offers more direct support, which can save you several steps in DLL creation. For more information, see Differences between Win16 and Win32 DLLs.

The differences between Win16 and Win32 DLLs require more than just a simple recompilation to turn your Win16 DLL into a Win32 DLL. For more information on porting 16-bit DLLs to Win32 DLLs, see the Knowledge Base article, “How to Port a 16-bit DLL to a Win32 DLL” (Q125688).


How do I convert my USRDLL to a regular DLL that uses the MFC shared library?

Home | Overview | How Do I | FAQ | Details | Sample

Note that the term USRDLL is no longer used in the Visual C++ documentation. A regular DLL that is statically linked to MFC has the same characteristics as the former USRDLL.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Converting your DLL to dynamically link to the MFC libraries requires more than just rebuilding the DLL with the MFC shared library. For detailed information on converting a regular DLL that statically links to MFC to a DLL that dynamically links to MFC, see the section titled “Converting DLLTRACE to Dynamically Link with the MFC DLL” in the abstract for the DLLTRACE sample.


How do I export data from a DLL?

Home | Overview | How Do I | FAQ | Details | Sample

It is possible for a Win32-based application to be able to address DLL global variables directly by name from within the executable. This is done by exporting global data names in a way that is similar to the way you export a DLL function name. For detailed information on how to export data from a DLL, see Using __declspec(dllimport) and __declspec(dllexport) and the Knowledge Base article “Exporting Data from a DLL or an Application” (Q90530).


How do I share data in my DLL with an application or with other DLLs?

Home | Overview | How Do I | FAQ | Details | Sample

Win32 DLLs are mapped into the address space of the calling process. By default, each process using a DLL has its own instance of the DLL global and static variables. If your DLL needs to share data with other Win32 DLLs loaded by a different application or with different mappings of the same DLL, then you can use either of the following approaches:

  • Create named data sections using the #pragma statement.

  • Use memory-mapped files.

To set up a new named section, use the #pragma data_seg directive. You then must specify the correct sharing attributes for this new named data section in your .DEF file. For more information about creating named data sections, see the following Knowledge Base articles:

  • "How to Share Data Between Different Mappings of a DLL" (Q125677).

  • "Specifying Shared and Nonshared Data in a DLL" (Q100634).

  • "How to Specify Shared and Nonshared Data in a DLL" (Q89817).

  • "Sharing All Data in a DLL" (Q109619).

However, if you need to share a C++ class instance, you should use a memory-mapped file, because each time a process attaches to the DLL, the constructor for the object is called. For example:

#pragma  data_seg(".myseg")
  _declspec(dllexport) CTest Counter1(0);
  _declspec(dllexport) short Counter2 = 0;
#pragma data_seg()

Assume that the variables Counter1 and Counter2 are incremented in a function in the DLL. The value of Counter2 increases as expected, but on each process attach, the constructor for Counter1 is called reinitializing it to zero. In order to share Counter1, you must use a memory-mapped file. For more information about memory-mapped files, see File Mapping in the Win32 SDK documentation.


Can a multithreaded application access an MFC DLL in different threads?

Home | Overview | How Do I | FAQ | Details | Sample

Multithreaded applications can access regular DLLs that dynamically link to MFC and extension DLLs from different threads. And as of Visual C++ version 4.2, an application can access regular DLLs that statically link to MFC from multiple threads created in the application.

Prior to version 4.2, only one external thread could attach to a regular DLL that statically linked to MFC. For more information about restrictions accessing regular DLLs that statically link to MFC from multiple threads (prior to Visual C++ version 4.2), see the Knowledge Base article, “Multiple Threads and MFC _USRDLLs” (Q122676).

Note that the term USRDLL is no longer used in the Visual C++ documentation. A regular DLL that is statically linked to MFC has the same characteristics as the former USRDLL.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.


Can an MFC DLL create multiple threads?

Home | Overview | How Do I | FAQ | Details | Sample

Except during initialization, an MFC DLL can safely create multiple threads as long as it uses the Win32 thread local storage (TLS) functions such as TlsAlloc to allocate thread local storage. However, if an MFC DLL uses __declspec(thread) to allocate thread local storage, the client application must be implicitly linked to the DLL. If the client application explicitly links to the DLL, the call to LoadLibrary will not successfully load the DLL. For more information on creating multiple threads inside MFC DLLs, see the Knowledge Base article, "PRB: LoadLibrary() Fails with _declspec(thread)" (Q118816).

An MFC DLL that creates a new MFC thread during startup will hang when it is loaded by an application. This includes whenever a thread is created by calling AfxBeginThread or CWinThread::CreateThread inside:

  • The InitInstance of a CWinApp-derived object in a regular DLL.

  • A supplied DllMain or RawDllMain function in a regular DLL.

  • A supplied DllMain or RawDllMain function in an Extension DLL.

For more information about creating threads during initialization, see the Knowledge Base article, "PRB: Cannot Create an MFC Thread During DLL Startup" (Q142243).


Are there any MFC classes or functions that cannot be used in an MFC DLL?

Home | Overview | How Do I | FAQ | Details | Sample

Extension DLLs use the CWinApp-derived class of the client application. They must not have their own CWinApp-derived class.

Regular DLLs must have a CWinApp-derived class and a single object of that application class, as does an MFC application. Unlike the CWinApp object of an application, the CWinApp object of the DLL does not have a main message pump.

The following MFC capabilities are not applicable in regular DLLs, either because of technical limitations or because those services are usually provided by the application.

  • CWinApp::Enable3dControls

  • CWinApp::SetDialogBkColor (color is ignored for message boxes)

Note that the CWinApp::Run mechanism does not apply to a DLL, since the application owns the main message pump. If the DLL opens modeless dialog boxes or has a main frame window of its own, the application's main message pump must call a routine exported by the DLL, which in turn calls the CWinApp::PreTranslateMessage member function of the DLL's application object.


How do I debug my DLL?

Home | Overview | How Do I | FAQ | Details | Sample

To debug a DLL using Visual C++, you must build a debugging version of the DLL and call it from an application. However, it is not necessary to build the debugging version of the calling application or to build the calling application with Visual C++. For more information on debugging a DLL, see Debugging DLLs or the following Knowledge Base articles:

  • "Debugging a Dynamic-Link Library (DLL) in Windows" (Q85221).

  • "Problems Loading a Debuggee That Uses a DLL" (Q119518).


What optimization techniques should I use to improve the client application's performance when loading?

What optimization techniques should I use to improve the client application’s performance when loading?

Home | Overview | How Do I | FAQ | Details | Sample

If your DLL is a regular DLL that is statically linked to MFC, changing it to a regular DLL that is dynamically linked to MFC will reduce the file size. For more information, see Which Kind of DLL to Use.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

If the DLL has a large number of exported functions, use a .DEF file to export the functions (instead of using __declspec(dllexport)) and use the .DEF file NONAME attribute on each exported function. The NONAME attribute causes only the ordinal value and not the function name to be stored in the DLL’s export table, which reduces the file size.

DLLs that are implicitly linked to an application are loaded when the application loads. To improve the performance when loading, try dividing the DLL into different DLLs. Put all the functions that the calling application needs immediately after loading into one DLL and have the calling application implicitly link to that DLL. Put the other functions that the calling application does not need right away into another DLL and have the application explicitly link to that DLL. For more information, see Determine Which Linking Method to Use.


There's a memory leak in my regular DLL, but my code looks fine. How can I find the memory leak?

There’s a memory leak in my regular DLL, but my code looks fine. How can I find the memory leak?

Home | Overview | How Do I | FAQ | Details | Sample

One possible cause of the memory leak is that MFC creates temporary objects that are used inside message handler functions. In regular DLLs, MFC does not automatically release memory allocated for these objects. For more information, see Solving Buffer Overwrites and Memory Leaks or the Knowledge Base article, “Cleaning Up Temporary MFC Objects in _USRDLL DLLs” (Q105286).

Note that the term USRDLL is no longer used in the Visual C++ documentation. A regular DLL that is statically linked to MFC has the same characteristics as the former USRDLL. The advice in the Knowledge Base article also applies to regular DLLs that are dynamically linked to MFC. The information in the above Knowledge Base article applies to both regular DLLs that statically link to MFC and regular DLLs that dynamically link to MFC.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.


How do I create a modal dialog box from within a regular DLL?

Home | Overview | How Do I | FAQ | Details | Sample

When creating a modal dialog box from within a regular DLL statically linked to the MFC, you must pass a valid parent window object to the CDialog constructor. For more information on creating a modal dialog box in a regular DLL that statically links to MFC, see the Knowledge Base article, “How to Create a Modal Dialog from Within a USRDLL” (Q121947). For sample code that creates a modal dialog box, see the sample DLLTRACE.

Note that the term USRDLL is no longer used in the Visual C++ documentation. A regular DLL that is statically linked to MFC has the same characteristics as the former USRDLL. The advice in the Knowledge Base article also applies to regular DLLs that are dynamically linked to MFC.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.


Exception Handling: Frequently Asked Questions

Home | Overview | How Do I | Details

This topic covers MFC exception handling, C++ exceptions, and structured exception handling (SEH).

Your question might be one of the questions listed in this topic.

What do you want to know more about?

  • What exception handling mechanisms are available?

  • Which exception mechanism should I use?


What Exception Handling Mechanisms Are Available?

Home | Overview | How Do I | Details

Visual C++ supports three different exception handling mechanisms:

  • C++ exceptions

  • Structured exception handling (SEH) for Windows NT

  • MFC exceptions

See Also Which exception handling mechanism should I use?


Which Exception Handling Mechanism Should I Use?

Home | Overview | How Do I | Details

Visual C++ supports three different exception handling mechanisms. Use the one that fits your situation:

  • C++ exceptions

    The Visual C++ the Microsoft Foundation Class Library (MFC).

  • Structured exception handling

    Windows NT supplies its own exception mechanism, called structured exception handling (SEH). SEH is not recommended for C++ or MFC programming.

  • MFC exception macros

    MFC has, since MFC version 1.0, supported an exception handling mechanism exposed through a set of macros. Although use of these macros is not recommended for new programming, the macros are still supported for backward compatibility. In programs that already use the macros, you can freely use C++ exceptions as well — during preprocessing, the macros evaluate to the exception handling keywords defined in the Visual C++ implementation of the C++ language as of Visual C++ version 2.0. You can leave existing exception macros in place while you begin to use C++ exceptions.


Internet Programming: Frequently Asked Questions

Home | Overview | How Do I | Details | Sample

Following are some frequently asked questions (FAQ) about Internet programming.

  1. How Are ISAPI Server Extensions and Filters Called?

  2. What Is the Difference Between an ISAPI Server Extension and a Filter?

  3. How Does ISAPI Compare with CGI?

  4. How Do I Have Multiple Filters and Extensions?

  5. What Are Some Programming Tips For Using ISAPI on IIS?

  6. What Are Some Memory and Resource Considerations?

  7. How Do I Use the MFC ISAPI Classes Without Linking to the MFC DLL?

  8. How Do I Script an ActiveX Control on a Web Page?


How Are ISAPI Server Extensions and Filters Called?

Home | Overview | How Do I | FAQ | Details | Sample

An Internet server extension (ISA) is a program you write to extend the capabilities of the server. An ISA is called when explicitly invoked by a client sending a URL that invokes your DLL. For example, http://yourserver/wwwquote.dll? asks the server named yourserver to run the DLL wwwquote. An HTTP request can also be sent when a user clicks a button on a Web page. This method is often used when a Web page is a form that collects information, which is passed as parameters to the DLL. For example, http://yourserver/wwwquote.dll?Issues?Method=ByCUSIP invokes the DLL and passes the parameter Method=ByCUSIP to the function Issues.

In contrast, an ISAPI filter is called each time a specified event occurs, no matter what request is being processed by the server. If you included SF_NOTIFY_URL_MAP, the flag for URL mapping, when requesting notifications, your OnURLMap function will be called each time a URL is mapped to your server, regardless of the content of the URL command. A filter can process, examine, and change data on each request to the server.


What Is the Difference Between an ISAPI Server Extension and a Filter?

Home | Overview | How Do I | FAQ | Details | Sample

A server extension: | A filter:
Runs when referenced in a URL. | Is called for every URL the server processes.
Is explicitly invoked, for example by http://myserver/myprog.dll?. | Runs automatically for any URL sent to the server if the registered event occurs.
Is loaded on demand, the first time a user calls it. | Is loaded when the service starts because of its registry entry.

Both server extensions and filters:

  • Share the process space of the service.

  • Must be thread safe.

  • Once loaded, remain in memory (until the service is stopped or the memory is needed by another process).


How Does ISAPI Compare with CGI?

Home | Overview | How Do I | FAQ | Details | Sample

ISAPI server extensions provide an alternative to the use of Common Gateway Interface (CGI) applications for Internet servers. Unlike CGI applications, ISAs run in the same address space as the HTTP server and have access to all the resources available to the HTTP server. ISAs have lower overhead than CGI applications because they do not require the creation of additional processes and do not perform time-consuming communications across process boundaries. Both extension and filter DLLs may be unloaded if the memory is needed by another process.

An Internet client calls an ISA through the HTTP server the same way it would call a CGI application. For example, a client might call a CGI application as:

http://sample/example.exe?Param1&Param2

It would call an ISA that performs the same function as:

http://sample/example.dll?Param1&Param2

ISAPI allows multiple commands in one DLL, implemented as member functions of the CHttpServer object in the DLL. CGI requires a separate name and URL mapping to a separate executable file for each task. Every new CGI request launches a new process, and each different request is contained in its own executable file, loaded and unloaded on each request, so overhead is higher than for ISAs.

ISAPI filters have no CGI equivalent. Filters provide the capability of pre-processing and post-processing of all data sent between the client and the server.


How Do I Have Multiple ISAPI Filters and Extensions?

Home | Overview | How Do I | FAQ | Details | Sample

You can have only one instance of a class derived from CHttpServer in a given DLL. You can have multiple DLLs installed, and each server extension DLL can have more than one command.

You can only have one instance of a class derived from CHttpFilter in a given DLL. One filter can register to receive multiple notifications. If you want to have a high-priority filter along with other notifications, use separate filters in separate DLLs, since all filters in the same DLL share the same priority.

Can my Filter and Server Extension Both Be in the Same DLL?

You can have one filter (receiving multiple notifications, if desired) and one server extension in the same DLL. This can be useful if you have a filter and a server extension that are related. For example, you may want to perform post-processing of data before sending it on to the client so that you can customize the look for a particular browser. Another instance would be to communicate between your filter and your extension. You can put the filter and application into the same DLL and add a key value header during the filter SF_NOTIFY_PREPROC_HEADERS notification. The application can obtain the key by looking up the corresponding context.

See Also Internet: Where Is...


What Are Some Programming Tips For Using ISAPI on IIS?

Home | Overview | How Do I | FAQ | Details | Sample

This article discusses programming tips that are specific to an ISAPI extension or filter running on Microsoft Internet Information Server (IIS). If you are running on other Web servers that support ISAPI, they may handle registry keys, memory, and loading of applications differently. Check the documentation for the Web server you are using for more information.

  • Remember that in IIS 1.0, an ISAPI filter is loaded when the service is started and not unloaded until the service stops. An ISAPI server extension is loaded the first time it is invoked and remains in memory until the service is shut down or the memory is needed for another process. Because your DLL will remain in memory for a long time, consider when to allocate resources, when to deallocate resources, and when to connect or disconnect from resources such as a data source.

How Do I Install a New Version of My Filter or Server Extension?

To install a new version of your filter or ISA, you must shut down the service, copy the DLL to the appropriate directory, update the registry if it’s a new filter, and restart the service.

When Is My DLL Loaded or Unloaded?

The registry key HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W3SVC/Parameters/FilterDLLs controls which filters are loaded when the service starts. It contains a list of filters, including their full paths, separated by commas. To load additional filters, stop the service, add your filter to the registry, and restart the service.

A server extension is loaded when first called by a client.

After the service is started, a filter remains in memory until the computer or the service is shut down. Once loaded, a server extension may also remain in memory until the computer or the service is shut down. You can force reloading of your extension DLL (for example, for debugging purposes) by specifying the registry setting HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W3SVC/Parameters/CacheExtensions=0. This setting doesn’t take effect until the service is restarted. Note that this setting should be used only while debugging. It has a negative impact on performance, and should never be used on a production server.


What Are Some Memory and Resource Considerations?

Home | Overview | How Do I | FAQ | Details | Sample

Must My Application Be Thread-Safe?

Yes. ISAPI runs as part of the Web server. On a multithreaded server such as Microsoft Internet Information Server, your application runs in the context of an NT service. Your application may be concurrently called multiple times from different threads. Data must be protected by critical sections.

How Can I Plan For Handling Simultaneous Requests?

ISAPI DLLs should support multiple simultaneous requests, and it is the responsibility of the ISAPI DLL developer to ensure that critical data is protected.

Web servers are built to concurrently handle multiple requests. Your application plus many others will be using the server. Client traffic of millions of users is seen daily at busy sites such as www.microsoft.com and popular search engines. Users want fast response, and they will cancel the request if it takes too long.

As mentioned earlier, be thread-safe. Do not hold on to resources or connections unless you need to. Don’t use global variables.

When you get a filter notification:

  1. Process the message quickly.

  2. Pass it along to the next filter.

  3. Don’t request high-priority notification unless you need to: for example, if you have an authentication filter that must run first, or if you are providing or preprocessing data used by other filters.


How Do I Use the MFC ISAPI Classes Without Linking to the MFC DLL?

Home | Overview | How Do I | FAQ | Details | Sample

To avoid linking to the MFC DLL

  1. Use the Settings command from the Project menu to edit the settings for your project. On the General tab, select the Don't Use MFC option in the Microsoft Foundation Classes drop-down box.

  2. Follow the comments generated by the ISAPI Extension Wizard in your ISAPI PROJECT.CPP file. Generate your own AfxGetResourceHandle() function and your own special DllMain() by uncommenting the lines in the file.

  3. Don’t include headers for MFC classes other than AFXISAPI.H.


How Do I Script an ActiveX Control on a Web Page?

Home | Overview | How Do I | FAQ | Details | Sample

An easy way to get started with scripting is by using an HTML authoring tool like Microsoft ActiveX Control Pad. This topic shows how to use ActiveX Control Pad to script CIRC3, a control sample used in the tutorials.

The ActiveX Control Pad is an authoring tool that lets you add ActiveX controls and scripting (such as JavaScript and VB Script) to your HTML pages with point-and-click ease. The ActiveX Control Pad also includes the new Microsoft HTML Layout Control, which supports windowless controls and provides new layout capabilities based on the HTML extensions proposed by the World Wide Web Consortium (W3C).

To install and run ActiveX Control Pad

  • The ActiveX Control Pad is freely available for downloading from the authoring tools section in the Microsoft Site Builder Workshop, accessible through www.microsoft.com. Follow the online instructions for installation.

To insert Circ3

  1. Start ActiveX Control Pad. It opens with a default HTML document including head and body tags.

  2. On the Edit menu, click Insert ActiveX Control.

  3. In the Insert ActiveX Control dialog box, click the Circ3 control to add it to the page.

    The control will be displayed in the Edit ActiveX Control window. You should see a rectangular control containing Circ31. Its properties can be set by changing values in the Properties window.

  4. Close the Edit ActiveX Control window.

    The OBJECT tag will be displayed on your HTML page, including the control’s class ID and other parameters used to instantiate the control at run time.

    Now you are ready to script the control.

To use VBScript to invoke properties and methods on Circ3

  1. Start ActiveX Control Pad and open the file created in the previous procedure containing a Circ3 control, if it is not already open.

  2. On the Tools menu, click Options, and then click Script.

  3. In the Script Options dialog box, select Visual Basic Scripting Edition as the Default Script Language and click OK.

  4. From the Tools menu, click Script Wizard.

    The following steps are all performed in the Script Wizard dialog box

  5. In the Select an Event list, click Window, and then click Load to add code to run when the control is loaded.

  6. In the Insert Actions list, click AboutBox, and click Insert Action. The following code to invoke the AboutBox method is inserted into the HTML file:
    <SCRIPT LANGUAGE="VBScript">
<!--
Sub window_onLoad()
call Circ31.AboutBox()
end sub
-->

To use JavaScript to invoke properties and methods on Circ3

  1. Start ActiveX Control Pad and open the file created in the previous procedure containing a Circ3 control, if it is not already open.

  2. On the Tools menu, click Options, and then click Script.

  3. In the Script Options dialog box, select JavaScript as the Default Script Language and click OK.

  4. From the Tools menu, click Script Wizard.

    The following steps are all performed in the Script Wizard dialog box.

  5. In the Select an Event list, click Window, and then click Load to add code to run when the control is loaded.

  6. In the Insert Actions list, click AboutBox, and click Insert Action. The following code to invoke the AboutBox method is inserted into the HTML file:

    <SCRIPT LANGUAGE="JavaScript" FOR="window" EVENT="onLoad()">

    <!--

    Circ31.AboutBox()

    -->

  7. Save the file and open it in a Browser. You should see the AboutBox displayed.

You can see how simple it is to add a control to a Web page using an authoring tool, and to use scripting to invoke its properties and methods. You can easily attach JavaScript or VBScript code to buttons on your HTML pages.


Details: Adding Program Functionality

Home | Overview | How Do I | FAQ

Sometimes you need broad, deep coverage of a subject, especially when you are learning a new skill. For such information about the topics under Adding Program Functionality, see the following families of articles:

  • Active Technology Topics

  • Assembler (Inline) Topics

  • Calling Conventions Topics

  • ClassView Topics

  • WizardBar Topics

  • ClassWizard Topics

  • CObject Class Topics

  • Collection Class Topics

  • Database Topics (General)

  • Database Topics (DAO)

  • Database Topics (ODBC)

  • Database Topics (Data-Bound Controls)

  • Date and Time Topics

  • DLL Topics

  • Exception Handling Topics (General)

  • Exception Handling Topics (MFC)

  • Exception Handling Topics (C++)

  • Exception Handling Topics (SEH)

  • Files Topics

  • International Programming Topics (developing for international markets)

  • Internet Topics

  • MAPI Topics

  • Memory Management Topics (MFC)

  • Message Handling and Mapping Topics

  • MFC Topics (General)

  • Mixed-Language Programming Topics

  • Multithreading Topics

  • OLE Topics

  • Reusing Code Topics

  • Serialization Topics

  • Strings Topics

  • Template Topics

  • Unicode Topics

  • Windows Sockets Topics

  • Win32 Topics

  • Windows 95 Functionality

  • Working with Classes Topics

See Also Adding User-Interface Features


Active Technology Topics

Home | Overview | How Do I

Active technologies (formerly called ActiveX) use the Component Object Model (COM) to enable software components to interact with one another in a networked environment, regardless of the language with which they were created. Active technologies can be used to create applications that run on the desktop or the Internet.

Active technologies include both client and server technologies, including the following:

  • Active document containment, supported in MFC versions 4.2 and later, allows users to view Active documents (such as Microsoft Excel or Word files) and activate the entire interface of the document's native application in the entire client area of an Active document container such as the Microsoft Office Binder or Microsoft Internet Explorer. The containers act as clients, while the documents are provided by Active document servers.

  • ActiveX controls are interactive objects that can be used in containers such as a Web site. For more information on ActiveX controls, see:

    ActiveX Controls (Adding User Interface Features)

    Internet First Steps: ActiveX Controls

    Internet Support: Overview

    Upgrade an Existing ActiveX Control to be Used on the Internet

  • Active Scripting controls the integrated behavior of one or more ActiveX controls and/or Java programs from a browser or server. For more information on Active Scripting, see:

    Script an ActiveX Control on a Web Page

    Active Technology on the Internet

  • Automation (formerly known as OLE Automation) makes it possible for one application to manipulate objects implemented in another application, or to “expose” objects so they can be manipulated.

    The automated object might be local or remote (on another machine accessible across a network). Automation is available for both OLE and COM objects.

For a discussion of what is still called OLE versus what is now called Active technology, see OLE Topics.

What do you want to know more about?

  • Overview of Active Document Containment

  • Example of Active Document Containment: Office Binder

  • Creating an Active Document Container Application

  • Active Document Containers

  • Active Document Servers

  • Active Documents

Sample Programs

  • The MFCBIND sample illustrates the implementation of an Active document container application.

  • The BINDSCRB sample illustrates the use of Active interfaces to provide Active documents.


Overview of Active Document Containment

Home | Overview | How Do I

Active document containment is a technology that provides a single frame in which to work with documents, instead of forcing you to create and use multiple application frames for each document type. It differs from basic OLE technology in that OLE works with embedded objects within a compound document in which only a single piece of content can be active. With active document containment you activate an entire document (that is, an entire application, including associated menus, toolbars, and so on) within the context of a single frame.

The active document containment technology was originally developed for Microsoft Office to implement Office Binder. However, the technology is flexible enough to support active document containers other than Office Binder, and can support document servers other than Office and Office-compatible applications.

The application that hosts active documents is called an Active document container. Examples of such containers are the Microsoft Office Binder or Microsoft Internet Explorer.

Active document containment is implemented as a set of extensions to OLE Documents, the compound document technology of OLE. The extensions are additional interfaces that allow an embeddable, in-place object to represent an entire document instead of a single piece of embedded content. As with OLE Documents, active document containment uses a container that provides the display space for Active documents, and servers that provide the user interface and manipulation capabilities for the Active documents themselves.

An Active document server is an application (such as Word, Excel, or PowerPoint) that supports one or more Active document classes, where each object itself supports the extension interfaces that allow the object to be activated in a suitable container.

An Active document (provided from an active document server such as Word or Excel) is essentially a full-scale, conventional document that is embedded as an object within another active document container. Unlike embedded objects, Active documents have complete control over their pages, and the full interface of the application (with all its underlying commands and tools) is available to the user to edit them.

An active document is best understood by distinguishing it from a standard OLE embedded object. Following the OLE convention, an embedded object is one that is displayed within the page of the document that owns it, and the document is managed by an OLE container. The container stores the embedded object’s data with the rest of the document. However, embedded objects are limited in that they do not control the page on which they appear.

Users of an Active document container application can create Active documents (called sections in Office Binder) using their favorite applications (provided these applictions are Active document enabled), yet the users can manage the resulting project as a single entity, which can be uniquely named, saved, printed, and so on. In the same way, a user of an Internet browser can treat the entire network, as well as local file systems, as a single document storage entity with the ability to browse the documents in that storage from a single location.


Example of Active Document Containment: Office Binder

Home | Overview | How Do I

The Office 95 Binder is an example of an active document container. An Office Binder includes two primary panes, as containers typically do. The left pane contains icons that correspond to Active documents in the Binder. Each document is called a section within the Binder. For example, a Binder can contain Word documents, PowerPoint files, Excel spreadsheets, and so on.

Clicking an icon in the left pane activates the corresponding Active document. The right pane of the Binder then displays the contents of the currently-selected Active document.

If you open and activate a Word document in a Binder, the Word menu bar and toolbars appear at the top of the view frame, and you can edit the document's contents using any Word command or tool. However, the menu bar is a combination of both the Binder's and Word's menu bars. Because both Binder and Word have Help menus, the contents of the respective menus are merged. Active document containers such as Office Binder automatically provide Help menu merging; for more information, see Help Menu Merging.

When you select an Active document of another application type, the Binder's interface changes to accommodate that of the Active document's application type. For example, if a Binder contains an Excel spreadsheet, you will observe that the menus in the Binder change when you select the Excel spreadsheet section.

There are, of course, other possible types of containers beside Binders. Windows Explorer uses the typical dual-pane interface in which the left pane uses a tree control to display a hierarchical list of directories in a drive or network, while the right pane displays the files contained in the currently-selected directory. An Internet browser-type of container (such as Microsoft Internet Explorer), rather than using a dual-pane interface, usually has a single frame and provides navigation using hyperlinks.


Creating an Active Document Container Application

Home | Overview | How Do I

The simplest and most recommended way to create an Active document container application is to create an MFC EXE container application using the MFC AppWizard, then modify the application to support active document containment.

To create an active document container application

  1. From the File menu, choose New.

  2. On the Projects tab, click MFC AppWizard (exe). Name the project MyProj.

  3. In Step 3 of the AppWizard, select the Container or Both container and server button.

  4. Click Finish.

  5. When the AppWizard finishes generating the application, select the FileView tab and open the following files:
    • Cntritem.cpp

    • Cntritem.h

    • MyProjview.cpp

    • MyProjview.h
  6. In Cntritem.cpp, make the following changes:
    • Replace COleClientItem with COleDocObjectItem. The latter class augments the OLE code with additional active document containment support.

    • Remove the implementation code from the body of CMyProjCntrlItem::OnActivate.

      The OnActivate code is not needed because the code in a normal container is used to guarantee that the item being activated is the only active item. Therefore, if there is another active item, it is deactivated first. A basic OLE container lets you have multiple embedded objects in a single document, so it needs this code. The default AppWizard-generated active document container is only set up to allow one Active document in the container at a time, so this code is unnecessary. Once you insert an object in your active document container, you cannot insert other objects.

  7. In Cntritem.h, make the following changes:
    • Replace COleClientItem with COleDocObjectItem
  8. In MyProjview.cpp, make the following changes:
    • In CMyProjView::OnPreparePrinting, add the following code:
      if (!CView::OnPreparePrinting(pInfo))
return FALSE;

if (!COleDocObjectItem::OnPreparePrinting(this, pInfo))
return FALSE;

return TRUE;

    OnPreparePrinting provides printing support. This code replaces DoPreparePrinting, which is the default print preparation.

    • Add an OnPrint override as follows:
      void CMyProjView::OnPrint(CDC* pDC, CPrintInfo* pInfo)
{
// TODO: add code to print the controls
if(pInfo->m_bDocObject)
COleDocObjectItem::OnPrint(this, pInfo, TRUE);
}

    Active document containment provides an improved printing scheme:

    • You can first call the Active document through its IPrint interface and tell it to print itself. This is different from previous OLE containment, in which the container had to render an image of the contained item onto the printer CDC object.

      •

    • If that fails, tell the contained item to print itself through its IOleCommandTarget interface

      •

    • If that fails, make your own rendering of the item.
      •

    The static member functions COleDocObjectItem::OnPrint and COleDocObjectItem::OnPreparePrinting, as implemented in the previous code, handle this improved printing scheme.
    9.

  9. In MyProjview.h, make the following changes:

    • Add the following to Overrides:

      virtual void OnPrint(CDC* pDC, CPrintInfo* pInfo);

      •

    10.

Note   In some functions, you do not need to change COleClientItem to COleDocObjectItem. Because a COleDocObjectItem object is a COleClientItem object, functions that do not specifically implement active document containment functionality (such as OnDestroy, OnCancelEditCntr, OnSetFocus, and OnSize) can implement functionality provided by COM client item objects.

Note also that COleDocument maintains a list of COleClientItem objects, not COleDocObjectItem objects.

  10. Add any implementation of your own and build the application.
    11.


Active Document Containers

Home | Overview | How Do I

An active document container allows you to work with several documents of different application types within a single frame (instead of forcing you to create and use multiple application frames for each document type).

MFC provides full support for Active document containers in the COleDocObjectItem class. You can use the MFC AppWizard to create an Active document container by selecting the Active document container checkbox in step 3 of the MFC AppWizard. See Creating an Active Document Container Application for more information.

What do you want to know more about?

  • Container Requirements

  • Document Site Objects

  • View Site Objects

  • Frame Object

  • Help Menu Merging

  • Programmatic Printing

  • Command Targets

Container Requirements

Active document support in an Active document container implies more than just interface implementations: it also requires knowledge of using the interfaces of a contained object. The same applies to Active document extensions, where the container must also know how to use those extension interfaces on the Active documents themselves.

An active document container that integrates Active documents must:

  • Be capable of handling object storage through the IPersistStorage interface, that is, it must provide an IStorage instance to each Active document.

  • Support the basic embedding features of OLE Documents, necessitating “site” objects (one per document or embedding) that implement IOleClientSite and IAdviseSink.

  • Support in-place activation of embedded objects or Active documents. The container’s site objects must implement IOleInPlaceSite and the container’s frame object must provide IOleInPlaceFrame.

  • Support the Active documents' extensions by implementing IOleDocumentSite to provide the mechanism for the container to talk to the document. Optionally, the container can implement the Active document interfaces IOleCommandTarget and IContinueCallback to pick up simple commands such as printing or saving.

The frame object, the view objects, and the container object can optionally implement IOleCommandTarget to support the dispatch of certain commands, as discussed in Command Targets. View and container objects can also optionally implement IPrint and IContinueCallback, to support programmatic printing, as discussed in Programmatic Printing.

The following figure shows the conceptual relationships between a container and its components (at left), and the Active document and its views (at right). The Active document manages storage and data, and the view displays or optionally prints that data. Interfaces in bold are those required for Active document participation; those bold and italic are optional. All other interfaces are required.

A document that supports only a single view can implement both the view and document components (that is, their corresponding interfaces) on a single concrete class. In addition, a container site that only supports one view at a time can combine the document site and the view site into a single concrete site class. The container’s frame object, however, must remain distinct, and the container’s document component is merely included here to give a complete picture of the architecture; it is not affected by the Active document containment architecture.

Document Site Objects

In the Active document containment architecture, a document site is the same as a client site object in OLE Documents with the addition of the IOleDocument interface:

interface IOleDocumentSite : IUnknown
    {
    HRESULT ActivateMe(IOleDocumentView *pViewToActivate);
    }

The document site is conceptually the container for one or more “view site” objects. Each view site object is associated with individual view objects of the document managed by the document site. If the container only supports a single view per document site, then it can implement the document site and the view site with a single concrete class.

View Site Objects

A container’s view site object manages the display space for a particular view of a document. In addition to supporting the standard IOleInPlaceSite interface, a view site also generally implements IContinueCallback for programmatic printing control. (Note that the view object never queries for IContinueCallback so it can actually be implemented on any object the container desires.)

A container that supports multiple views must be able to create multiple view site objects within the document site. This provides each view with separate activation and deactivation services as provided through IOleInPlaceSite.

Frame Object

The container’s frame object is, for the most part, the same frame that is used for in-place activation in OLE Documents, that is, the one that handles menu and toolbar negotiation. A view object has access to this frame object through IOleInPlaceSite::GetWindowContext, which also provides access to the container object representing the container document (which can handle pane-level toolbar negotiation and contained object enumeration).

An Active document container can augment the frame by adding IOleCommandTarget. This allows it to receive commands that originate in the Active document’s user interface in the same way that this interface can allow a container to send the same commands (such as File New, Open, Save As, Print; Edit Copy, Paste, Undo, etc.) to an active document. For more information, see Command Targets.


Help Menu Merging

Home | Overview | How Do I

When an object is active within a container, the menu merging protocol of OLE Documents gives the object complete control of the Help menu. As a result, the container’s Help topics are not available unless the user deactivates the object. The Active document containment architecture expands on the rules for in-place menu merging to allow both the container and an active Active document to share the menu. The new rules are simply additional conventions about what component owns what part of the menu and how the shared menu is constructed.

The new convention is simple. In Active documents, the Help menu has two top-level menu items organized as follows:

Help
   Container Help >
   Object Help    >

For example, when a Word section is active in the Office Binder, then the Help menu would appear as follows:

Help
   Binder Help >
   Word Help   >

Both menu items are cascading menus under which any additional menu items specific to the container and the object are provided to the user. What items appear here will vary with the container and objects involved.

To construct this merged Help menu, the Active document containment architecture modifies the normal OLE Documents procedure. According to OLE Documents, the merged menu bar can have six groups of menus, namely File, Edit, Container, Object, Window, Help, in that order. In each group there can be zero or more menus. The groups File, Container, and Window belong to the container and the groups Edit, Object, and Help belong to the object. When the object wants to do menu merging, it creates a blank menu bar and passes it to the container. The container then inserts its menus, by calling IOleInPlaceFrame::InsertMenus. The object also passes a structure that is an array of six LONG values (OLEMENUGROUPWIDTHS). After inserting the menus, the container marks how many menus it added in each one of its groups, and then returns. Then the object inserts its menus, paying attention to the count of menus in each container group. Finally, the object passes the merged menu bar and the array (which contains the count of menus in each group) to OLE, which returns an opaque “menu descriptor” handle. Later the object passes that handle and the merged menu bar to the container, via IOleInPlaceFrame::SetMenu. At this time, the container displays the merged menu bar and also passes the handle to OLE, so that OLE can do proper dispatching of menu messages.

In the modified Active document procedure, the object must first initialize the OLEMENUGROUPWIDTHS elements to zero before passing it to the container. Then the container performs a normal menu insertion with one exception: The container inserts a Help menu as the last item and stores a value of 1 in the last (sixth) entry of the OLEMENUGROUPWIDTHS array (that is, width[5] which belongs to the object’s Help group). This Help menu will have only one item which is a submenu, the “Container Help >” cascade menu as described above.

The object then executes its normal menu insertion code, except that before inserting its Help menu, it checks the sixth entry of the OLEMENUGROUPWIDTHS array. If the value is 1 and the name of the last menu is Help (or the appropriate localized string), then the object inserts its Help menu as submenu of the container’s Help menu.

The object then sets the sixth element of OLEMENUGROUPWIDTHS to zero and increments the fifth element by one. This lets OLE know that the Help menu belongs to the container and the menu messages corresponding to that menu (and its submenus) should be routed to the container. It is then the container’s responsibility to forward WM_INITMENUPOPUP, WM_SELECT, WM_COMMAND, and other menu-related messages that belong to the object’s portion of the Help menu. (This is accomplished by using WM_INITMENU to clear a flag that tells the container whether or not the user has navigated into the object’s Help menu. The container then watches WM_MENUSELECT for entry into or exit from any item on the Help menu that the container did not add itself. On entry, it means the user has navigated into an object menu, so the container sets the “in object Help menu” flag and uses the state of that flag to forward any WM_MENUSELECT, WM_INITMENUPOPUP, and WM_COMMAND messages, as a minimum, to the object window. (On exit, the container clears the flag and then processes these same messages itself.) The container should use the window returned from the object’s IOleInPlaceActiveObejct::GetWindow function as the destination for these messages.

If the object detects a zero in the sixth element of OLEMENUGROUPWIDTHS, it proceeds according to the normal OLE Documents rules. This procedure covers containers that do participate in Help menu merging as well as those that do not.

When the object calls IOleInPlaceFrame::SetMenu, before displaying the merged menu bar, the container checks whether the Help menu has an additional submenu, in addition to what the container has inserted. If so, the container leaves its Help menu in the merged menu bar. If the Help menu does not have an additional submenu, the container will remove its Help menu from the merged menu bar. This procedure covers objects that participate in Help menu merging as well as those that do not.

Finally, when it is time to disassemble the menu, the object removes the inserted Help menu in addition to removing the other inserted menus. When the container removes its menus, it will remove its Help menu in addition to the other menus that it has inserted.


Programmatic Printing

Home | Overview | How Do I

OLE provided the means to uniquely identify persistent documents (GetClassFile) and load them into their associated code (CoCreateInstance, QueryInterface(IID_IPersistFile), QueryInterface(IID_IPersistStorage), IPersistFile::Load, and IPersistStorage::Load). To further enable printing documents, Active document containment (using an existing OLE design not shipped with OLE 2.0 originally) introduces a base-standard printing interface, IPrint, generally available through any object that can load the persistent state of the document type. Each view of an Active document can optionally support the IPrint interface to provide these capabilities.

The IPrint interface is defined as follows:

interface IPrint : IUnknown
    {
    HRESULT SetInitialPageNum([in] LONG nFirstPage);
    HRESULT GetPageInfo([out] LONG *nFirstPage, [out] LONG *pcPages);
    HRESULT Print([in] DWORD grfFlags, [in,out] DVTARGETDEVICE **pptd
        , [in,out] PAGESET ** ppPageSet , [in,out] STGMEDIUM **ppstgmOptions
        , [in] IContinueCallback* pCallback, [in] LONG nFirstPage
        ,[out] LONG *pcPagesPrinted, [out] LONG *pnPageLast);
    };

Clients and containers simply use IPrint::Print to instruct the document to print itself once that document is loaded, specifying printing control flags, the target device, the pages to print, and additional options. The client can also control the continuation of printing through the interface IContinueCallback (see below).

In addition, IPrint::SetInitialPageNum supports the ability to print a series of documents as one by numbering pages seamlessly, obviously a benefit for active document containers like Office Binder. IPrint::GetPageInfo makes displaying pagination information simple by allowing the caller to retrieve the starting page number previously passed to SetInitialPageNum (or the document’s internal default starting page number) and the number of pages in the document.

Objects that support IPrint are marked in the registry with the “Printable” key stored under the object’s CLSID:

HKEY_CLASSES_ROOT\CLSID\{...}\Printable

IPrint is usually implemented on the same object that supports either IPersistFile or IPersistStorage. Callers note the capability to programmatically print the persistent state of some class by looking in the registry for the “Printable” key. Currently, “Printable” indicates support for at least IPrint; other interfaces may be defined in the future which would then be available through QueryInterface where IPrint simply represents the base level of support.

During a print procedure, you may want the client or container that initiated the printing to control whether or not the printing should continue. For example, the container may support a “Stop Print” command that should terminate the print job as soon as possible. To support this capability, the client of a printable object can implement a small notification sink object with the interface IContinueCallback:

interface IContinueCallback : IUnknown
    {
    HRESULT FContinue(void);
    HRESULT FContinuePrinting([in] LONG cPagesPrinted, [in] LONG nCurrentPage
        , [in] LPOLESTR pszPrintStatus);
    };

This interface is designed to be useful as a generic continuation callback function that takes the place of the various continuation procedures in the Win32 API (such as the AbortProc for printing and the EnumMetafileProc for metafile enumeration). Thus this interface design is useful in a wide variety of time-consuming processes.

In the most generic cases, the IContinueCallback::FContinue function is called periodically by any lengthy process. The sink object returns S_OK to continue the operation, and S_FALSE to stop the procedure as soon as possible.

FContinue, however, is not used in the context of IPrint::Print; rather, printing uses IContinueCallback::FContinuePrint. Any printing object should periodically call FContinuePrinting passing the number of pages that have been printing, the number of the page being printed, and an additional string describing the print status that the client may choose to display to the user (such as “Page 5 of 19”).


Command Targets

Home | Overview | How Do I

The command dispatch interface IOleCommandTarget defines a simple and extensible mechanism to query and execute commands. This mechanism is simpler than Automation’s IDispatch because it relies entirely on a standard set of commands; commands rarely have arguments, and no type information is involved (type safety is diminished for command arguments as well).

In the command dispatch interface design, each command belongs to a “command group” which is itself identified with a GUID. Therefore, anyone can define a new group and define all the commands within that group without any need to coordinate with Microsoft or any other vendor. (This is essentially the same means of definition as a dispinterface plus dispIDs in Automation. There is overlap here, although this command routing mechanism is only for command routing and not for scripting/programmability on a large scale as Automation handles.)

IOleCommandTarget handles the following scenarios:

  • When an object is in-place activated, only the object’s toolbars are typically displayed and the object’s toolbars may have buttons for some of the container commands like Print, Print Preview, Save, New, Zoom, etc. (In-place activation standards recommend that objects remove such buttons from their toolbars, or at least disable them. This design allows those commands to be enabled and yet routed to the right handler.) Currently, there is no mechanism for the object to dispatch these commands to the container.

  • When an active document is embedded in an active document container (such as Binder), the container may need to send commands such Print, Page Setup, Properties, etc. to the contained Active document.

Obviously this simple command routing could be handled through existing Automation standards and IDispatch. However, the overhead involved with IDispatch is more than is necessary here, so IOleCommandTarget provides a simpler means to achieve the same ends:

interface IOleCommandTarget : IUnknown
    {
    HRESULT QueryStatus([in] GUID *pguidCmdGroup, [in] ULONG cCmds
        , [in,out][size_is(cCmds)] OLECMD *prgCmds, [in,out] OLECMDTEXT *pCmdText);
    HRESULT Exec([in] GUID *pguidCmdGroup, [in] DWORD nCmdID, [in] DWORD nCmdExecOpt
        , [in] VARIANTARG *pvaIn, [in,out] VARIANTARG *pvaOut);
    }

The QueryStatus method here tests whether a particular set of commands, the set being identified with a GUID, is supported. This call fills an array of OLECMD values (structures) with the supported list of commands as well as returning text describing the name of a command and/or status information. When the caller wishes to invoke a command, it can pass the command (and the set GUID) to Exec along with options and arguments, getting back a return value.


Active Document Servers

Home | Overview | How Do I

Active document servers such as Microsoft Office Binder or Internet Explorer host documents of other application types called Active documents. Unlike OLE embedded objects (which are simply displayed within the page of another document), Active documents provide the full interface and complete native functionality of the server application that creates them. Users can create documents using the full power of their favorite applications (if they are Active document enabled), yet can treat the resulting project as a single entity.

Active documents can have more than one page and are always in-place active. Active documents control part of the user interface, merging their menus with the File and Help menus of the container. They occupy the entire editing area of the container and control the views and the layout of the printer page (margins, footers, and so on).

MFC implements Active document servers with document/view interfaces, command dispatch maps, printing, menu management, and registry management. Specific programming requirements are discussed in Active documents.

MFC supports Active documents with the CDocObjectServer class, derived from CCmdTarget, and CDocObjectServerItem, derived from COleServerItem. MFC supports Active document containers with the COleDocObjectItem class, derived from COleClientItem.

CDocObjectServer maps the Active document interfaces and initializes and activates an Active document. MFC also provides macros to handle command routing in Active documents. To use Active documents in your application, include AfxDocOb.h in your StdAfx.h file.

A regular MFC server hooks up its own COleServerItem-derived class. MFC AppWizard generates this class for you if you select the Mini-server or Full-server check box to give your application server compound document support. If you also select the Active document server check box, AppWizard will generate a class derived from CDocObjectServerItem instead.

The COleDocObjectItem class allows an OLE container to become an Active document container. You can use the MFC AppWizard to create an Active document container by selecting the Active document container checkbox in Step 3 of the MFC AppWizard. For more information, see Creating an Active Document Container Application.


Active Documents

Home | Overview | How Do I

Active documents extend the compound document technology of OLE. These extensions are provided in the form of additional interfaces that manage views, so that objects can function within containers and yet retain control over their display and printing functions. This process makes it possible to display documents both in foreign frames (such as the Microsoft Office Binder or Microsoft Internet Explorer) and in native frames (such as the product’s own view ports).

This section describes the functional requirements for Active documents. The Active document owns a set of data and has access to storage where the data can be saved and retrieved. It can create and manage one or more views on its data. In addition to supporting the usual embedding and in-place activation interfaces of OLE documents, the Active document communicates its ability to create views through IOleDocument. Through this interface, the container can ask to create (and possibly enumerate) the views that the Active document can display. Through this interface, the Active document can also provide miscellaneous information about itself, such as whether it supports multiple views or complex rectangles.

The following is the IOleDocument interface. Note that the IEnumOleDocumentViews interface is a standard OLE enumerator for IOleDocumentView * types.

interface IOleDocument : IUnknown
    {
    HRESULT CreateView([in] IOleInPlaceSite *pIPSite, [in] IStream *pstm
        , [in] DWORD dwReserved, [out] IOleDocumentView **ppView);
    HRESULT GetDocMiscStatus([out] DWORD *pdwStatus);
    HRESULT EnumViews([out] IEnumOleDocumentViews **ppEnum
        , [out] IOleDocumentView **ppView);
    }

Every Active document must have a view frame provider with this interface. If the document is not embedded within a container, the Active document server itself must provide the view frame. However, when the Active document is embedded in an Active document container, the container provides the view frame.

An Active document can create one or more types of views of its data (for example, normal, outline, page layout, and so on). Views act like filters through which the data can be seen. Even if the document has only one type of view, you may still wish it to support multiple views as a means of supporting new window functionality (for example, the New Window item on the Window menu in Office applications).

Requirements for Active Documents

An active document that can be displayed in an active document container must:

  • Use OLE’s Compound Files as its storage mechanism by implementing IPersistStorage.

  • Support the basic embedding features of OLE Documents, including Create From File. This necessitates the interfaces IPersistFile, IOleObject, and IDataObject.

  • Support one or more views, each of which is capable of in-place activation. That is, the views must support the interface IOleDocumentView as well as the interfaces IOleInPlaceObject and IOleInPlaceActiveObject (using the container’s IOleInPlaceSite and IOleInPlaceFrame interfaces).

  • Support the standard Active document interfaces IOleDocument, IOleCommandTarget, and IPrint.

Knowledge of when and how to use the container-side interfaces is implied in these requirements.

Requirements for View Objects

An Active document can create one or more views of its data. Functionally, these views are like ports onto a particular method for displaying the data. If an Active document only supports a single view, the Active document and that single view can be implemented using a single class. IOleDocument::CreateView simply returns the same object’s IOleDocumentView interface pointer.

To be represented within an active document container, a view component must support IOleInPlaceObject and IOleInPlaceActiveObject in addition to IOleDocumentView:

interface IOleDocumentView : IUnknown
    {
    HRESULT SetInPlaceSite([in] IOleInPlaceSite *pIPSite);
    HRESULT GetInPlaceSite([out] IOleInPlaceSite **ppIPSite);
    HRESULT GetDocument([out] IUnknown **ppunk);
    [input_sync] HRESULT SetRect([in] LPRECT prcView);
    HRESULT GetRect([in] LPRECT prcView);
    [input_sync] HRESULT SetRectComplex([in] LPRECT prcView
        , [in] LPRECT prcHScroll, [in] LPRECT prcVScroll
        , [in] LPRECT prcSizeBox);
    HRESULT Show([in] BOOL fShow);
    HRESULT UIActivate([in] BOOL fUIActivate);
    HRESULT Open(void);
    HRESULT CloseView([in] DWORD dwReserved);
    HRESULT SaveViewState([in] IStream *pstm);
    HRESULT ApplyViewState([in] IStream *pstm);
    HRESULT Clone([in] IOleInPlaceSite *pIPSiteNew, [out] IOleDocumentView **ppViewNew);
    }

Every view has an associated view site, which encapsulates the view frame and the view port (HWND and a rectangular area in that window). The site exposes this functionality though the standard IOleInPlaceSite interface. Note that it is possible to have more than one view port on a single HWND.

Typically each type of view has a different printed representation. Hence views and the corresponding view sites should implement the printing interfaces if IPrint and IContinueCallback, respectively. The view frame must negotiate with the view provider through IPrint when printing begins, so that headers, footers, margins, and related elements are printed correctly. The view provider notifies the frame of printing-related events through IContinueCallback. For more information on the use of these interfaces, see Programmatic Printing.

Note that if an active document only supports a single view, then the Active document and that single view can be implemented using a single concrete class. IOleDocument::CreateView simply returns the same object’s IOleDocumentView interface pointer. In short, it is not necessary that there be two separate object instances when only one view is required.

A view object can also be a command target. By implementing IOleCommandTarget a view can receive commands that originate in the container’s user interface (such as New, Open, Save As, Print on the File menu; and Copy, Paste, Undo on the Edit menu). For more information, see Command Targets.


Assembler (Inline) Topics

Home | Overview | How Do I

This article family explains what you need to know to use the Visual C/C++ inline assembler with Intel x86-series compatible processors (such as the AMD386 and the i486™).

What do you want to know more about?

  • Advantages of Inline Assembly

  • The __asm Keyword

  • Using Assembly Language in __asm Blocks

  • Using C or C++ in __asm Blocks

  • Using and Preserving Registers in Inline Assembly

  • Jumping to Labels in Inline Assembly

  • Calling C Functions in Inline Assembly

  • Calling C++ Functions in Inline Assembly

  • Defining __asm Blocks as C Macros

  • Optimizing Inline Assembly


Advantages of Inline Assembly

Home | Overview | How Do I

Because the inline assembler doesn’t require separate assembly and link steps, it is more convenient than a separate assembler. Inline assembly code can use any C variable or function name that is in scope, so it is easy to integrate it with your program’s C code. Because the assembly code can be mixed inline with C or C++ statements, it can do tasks that are cumbersome or impossible in C or C++.

The uses of inline assembly include:

  • Writing functions in assembly language.

  • Spot-optimizing speed-critical sections of code.

  • Making direct hardware access for device drivers.

  • Writing prolog and epilog code for “naked” calls.

Inline assembly is a special-purpose tool. If you plan to port an application to different machines, you’ll probably want to place machine-specific code in a separate module. Because the inline assembler doesn’t support all of Microsoft Macro Assembler’s (MASM) macro and data directives, you may find it more convenient to use MASM for such modules.


The __asm Keyword

Home | Overview | How Do I

The __asm keyword invokes the inline assembler and can appear wherever a C or C++ statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces. The term “__asm block” here refers to any instruction or group of instructions, whether or not in braces.

The following code fragment is a simple __asm block enclosed in braces:

__asm
{
   mov al, 2
   mov dx, 0xD007
   out al, dx
}

Alternatively, you can put __asm in front of each assembly instruction:

__asm mov al, 2
__asm mov dx, 0xD007
__asm out al, dx

Because the __asm keyword is a statement separator, you can also put assembly instructions on the same line:

__asm mov al, 2   __asm mov dx, 0xD007   __asm out al, dx

All three examples generate the same code, but the first style (enclosing the __asm block in braces) has some advantages. The braces clearly separate assembly code from C or C++ code and avoid needless repetition of the __asm keyword. Braces can also prevent ambiguities. If you want to put a C or C++ statement on the same line as an __asm block, you must enclose the block in braces. Without the braces, the compiler cannot tell where assembly code stops and C or C++ statements begin. Finally, because the text in braces has the same format as ordinary MASM text, you can easily cut and paste text from existing MASM source files.

Unlike braces in C and C++, the braces enclosing an __asm block don’t affect variable scope. You can also nest __asm blocks; nesting does not affect variable scope.


Using Assembly Language in __asm Blocks

Home | Overview | How Do I

The inline assembler has much in common with other assemblers. For example, it accepts any expression that is legal in MASM. This section describes the use of assembly-language features in __asm blocks.

What do you want to know more about?

  • Instruction Set for Inline Assembly

  • MASM Expressions in Inline Assembly

  • Data Directives and Operators in Inline Assembly

  • EVEN and ALIGN Directives

  • MASM Macro Directives in Inline Assembly

  • Segment References in Inline Assembly

  • Type and Variable Sizes in Inline Assembly

  • Assembly-Language Comments

  • The _emit Pseudoinstruction

  • Debugging and Listings for Inline Assembly

  • Intel’s MMX Instruction Set


Instruction Set for Inline Assembly

Home | Overview | How Do I

The inline assembler supports the full instruction set of the Intel 486 processor. Additional instructions supported by the target processor can be created with the _emit Pseudoinstruction.


MASM Expressions in Inline Assembly

Home | Overview | How Do I

Inline assembly code can use any MASM expression, which is any combination of operands and operators that evaluates to a single value or address.


Data Directives and Operators in Inline Assembly

Home | Overview | How Do I

Although an __asm block can reference C or C++ data types and objects, it cannot define data objects with MASM directives or operators. Specifically, you cannot use the definition directives DB, DW, DD, DQ, DT, and DF, or the operators DUP or THIS. MASM structures and records are also unavailable. The inline assembler doesn’t accept the directives STRUC, RECORD, WIDTH, or MASK.


EVEN and ALIGN Directives

Home | Overview | How Do I

Although the inline assembler doesn’t support most MASM directives, it does support EVEN and ALIGN. These directives put NOP (no operation) instructions in the assembly code as needed to align labels to specific boundaries. This makes instruction-fetch operations more efficient for some processors.


MASM Macro Directives in Inline Assembly

Home | Overview | How Do I

The inline assembler is not a macro assembler. You cannot use MASM macro directives (MACRO, REPT, IRC, IRP, and ENDM) or macro operators (<>, !, &, %, and .TYPE). An __asm block can use C preprocessor directives, however. See Using C or C++ in __asm Blocks for more information.


Segment References in Inline Assembly

Home | Overview | How Do I

You must refer to segments by register rather than by name (the segment name _TEXT is invalid, for instance). Segment overrides must use the register explicitly, as in ES:[BX].


Type and Variable Sizes in Inline Assembly

Home | Overview | How Do I

The LENGTH, SIZE, and TYPE operators have a limited meaning in inline assembly. They cannot be used at all with the DUP operator (because you cannot define data with MASM directives or operators). But you can use them to find the size of C or C++ variables or types:

  • The LENGTH operator can return the number of elements in an array. It returns the value 1 for non-array variables.

  • The SIZE operator can return the size of a C or C++ variable. A variable’s size is the product of its LENGTH and TYPE.

  • The TYPE operator can return the size of a C or C++ type or variable. If the variable is an array, TYPE returns the size of a single element of the array.

For example, if your program has an 8-element int array,

int arr[8];

the following C and assembly expressions yield the size of arr and its elements.

__asm | C | Size
LENGTH arr | sizeof(arr)/sizeof(arr[0]) | 8
SIZE arr | sizeof(arr) | 16
TYPE arr | sizeof(arr[0]) | 2


Assembly-Language Comments

Home | Overview | How Do I

Instructions in an __asm block can use assembly-language comments:

__asm mov ax, offset buff ; Load address of buff

Because C macros expand into a single logical line, avoid using assembly-language comments in macros. (See Defining __asm Blocks as C Macros.) An __asm block can also contain C-style comments; for more information, see Using C or C++ in __asm Blocks.


The _emit Pseudoinstruction

Home | Overview | How Do I

The _emit pseudoinstruction is similar to the DB directive of MASM. You use _emit to define a single immediate byte at the current location in the current text segment. However, _emit can define only one byte at a time, and it can only define bytes in the text segment. It uses the same syntax as the INT instruction.

The following fragment places the given bytes into the code:

#define randasm __asm _emit 0x4A __asm _emit 0x43 __asm _emit 0x4B
 .
 .
 .
__asm {
     randasm
     }


Debugging and Listings for Inline Assembly

Home | Overview | How Do I

Programs containing inline assembly code can be debugged with a source-level debugger if you compile with the /Zi option.

Within the debugger, you can set breakpoints on both C or C++ and assembly-language lines. If you enable mixed assembly and source mode, you can display both the source and disassembled form of the assembly code.

Note that putting multiple assembly instructions or source language statements on one line can hamper debugging. In source mode, you can use the debugger to set breakpoints on a single line but not on individual statements on the same line. The same principle applies to an __asm block defined as a C macro, which expands to a single logical line.

If you create a mixed source and assembly listing with the /FAs compiler option, the listing contains both the source and assembly forms of each assembly-language line. Macros are not expanded in listings, but they are expanded during compilation.


Intel's MMX Instruction Set

Home | Overview | How Do I

The Visual C++ compiler allows you to use Intel's MMX (multimedia extension) instruction set in the inline assembler. The MMX instructions are also supported by the debugger disassembly. The MMX registers are not supported in the debugger register window. The compiler generates a warning message if the function contains MMX instructions, but does not have an EMMS instruction to empty the multimedia state. For more information, see the Intel Web site.


Using C or C++ in __asm Blocks

Home | Overview | How Do I

Because inline assembly instructions can be mixed with C or C++ statements, they can refer to C or C++ variables by name and use many other elements of those languages.

An __asm block can use the following language elements:

  • Symbols, including labels and variable and function names

  • Constants, including symbolic constants and enum members

  • Macros and preprocessor directives

  • Comments (both /* */ and // )

  • Type names (wherever a MASM type would be legal)

  • typedef names, generally used with operators such as PTR and TYPE or to specify structure or union members

Within an __asm block, you can specify integer constants with either C notation or assembler radix notation (0x100 and 100h are equivalent, for example). This allows you to define (using #define) a constant in C and then use it in both C or C++ and assembly portions of the program. You can also specify constants in octal by preceding them with a 0. For example, 0777 specifies an octal constant.

What do you want to know more about?

  • Using Operators in __asm Blocks

  • Using C or C++ Symbols_in __asm Blocks

  • Accessing C or C++ Data in __asm Blocks

  • Writing Functions with Inline Assembly


Using Operators in __asm Blocks

Home | Overview | How Do I

An __asm block cannot use C or C++ specific operators, such as the << operator. However, operators shared by C and MASM, such as the * operator, are interpreted as assembly-language operators. For instance, outside an __asm block, square brackets ([ ]) are interpreted as enclosing array subscripts, which C automatically scales to the size of an element in the array. Inside an __asm block, they are seen as the MASM index operator, which yields an unscaled byte offset from any data object or label (not just an array). The following code illustrates the difference:

int array[10];

__asm mov array[6], bx ;  Store BX at array+6 (not scaled)

array[6] = 0;         /* Store 0 at array+12 (scaled) */

The first reference to array is not scaled, but the second is. Note that you can use the TYPE operator to achieve scaling based on a constant. For example, the following statements are equivalent:

__asm mov array[6 * TYPE int], 0 ; Store 0 at array + 12

array[6] = 0;                   /* Store 0 at array + 12 */


Using C or C++ Symbols in __asm Blocks

Home | Overview | How Do I

An __asm block can refer to any C or C++ symbol in scope where the block appears. (C and C++ symbols are variable names, function names, and labels; that is, names that aren’t symbolic constants or enum members. You cannot call C++ member functions.)

A few restrictions apply to the use of C and C++ symbols:

  • Each assembly-language statement can contain only one C or C++ symbol. Multiple symbols can appear in the same assembly instruction only with LENGTH, TYPE, and SIZE expressions.

  • Functions referenced in an __asm block must be declared (prototyped) earlier in the program. Otherwise, the compiler cannot distinguish between function names and labels in the __asm block.

  • An __asm block cannot use any C or C++ symbols with the same spelling as MASM reserved words (regardless of case). MASM reserved words include instruction names such as PUSH and register names such as SI.

  • Structure and union tags are not recognized in __asm blocks.


Accessing C or C++ Data in __asm Blocks

Home | Overview | How Do I

A great convenience of inline assembly is the ability to refer to C or C++ variables by name. An __asm block can refer to any symbols, including variable names, that are in scope where the block appears. For instance, if the C variable var is in scope, the instruction

__asm mov eax, var

stores the value of var in EAX.

If a class, structure, or union member has a unique name, an __asm block can refer to it using only the member name, without specifying the variable or typedef name before the period (.) operator. If the member name is not unique, however, you must place a variable or typedef name immediately before the period operator. For example, the following structure types share same_name as their member name:

struct first_type
{
   char *weasel;
   int same_name;
};

struct second_type
{
   int wonton;
   long same_name;
};

If you declare variables with the types

struct first_type hal;
struct second_type oat;

all references to the member same_name must use the variable name because same_name is not unique. But the member weasel has a unique name, so you can refer to it using only its member name:

__asm
{
   mov ebx, OFFSET hal
   mov ecx, [ebx]hal.same_name ; Must use 'hal'
   mov esi, [ebx].weasel       ; Can omit 'hal'
}

Note that omitting the variable name is merely a coding convenience. The same assembly instructions are generated whether or not the variable name is present.

You can access data members in C++ without regard to access restrictions. However, you cannot call member functions.


Writing Functions with Inline Assembly

Home | Overview | How Do I

If you write a function with inline assembly code, it’s easy to pass arguments to the function and return a value from it. The following examples compare a function first written for a separate assembler and then rewritten for the inline assembler. The function, called power2, receives two parameters, multiplying the first parameter by 2 to the power of the second parameter. Written for a separate assembler, the function might look like this:

; POWER.ASM
; Compute the power of an integer
;
       PUBLIC _power2
_TEXT SEGMENT WORD PUBLIC 'CODE'
_power2 PROC

        push ebp        ; Save EBP
        mov ebp, esp    ; Move ESP into EBP so we can refer
                        ;   to arguments on the stack
        mov eax, [ebp+4] ; Get first argument
        mov ecx, [ebp+6] ; Get second argument
        shl eax, cl     ; EAX = EAX * ( 2 ^ CL )
        pop ebp         ; Restore EBP
        ret             ; Return with sum in EAX

_power2 ENDP
_TEXT   ENDS
        END

Since it’s written for a separate assembler, the function requires a separate source file and assembly and link steps. C and C++ function arguments are usually passed on the stack, so this version of the power2 function accesses its arguments by their positions on the stack. (Note that the MODEL directive, available in MASM and some other assemblers, also allows you to access stack arguments and local stack variables by name.)

The POWER2.C program writes the power2 function with inline assembly code:

/* POWER2.C */
#include <stdio.h>

int power2( int num, int power );

void main( void )
{
   printf( "3 times 2 to the power of 5 is %d\n", \
           power2( 3, 5) );
}
int power2( int num, int power )
{
   __asm
   {
      mov eax, num    ; Get first argument
      mov ecx, power  ; Get second argument
      shl eax, cl     ; EAX = EAX * ( 2 to the power of CL )
   }
   /* Return with result in EAX */
}

The inline version of the power2 function refers to its arguments by name and appears in the same source file as the rest of the program. This version also requires fewer assembly instructions.

Because the inline version of power2 doesn’t execute a C return statement, it causes a harmless warning if you compile at warning level 2 or higher. The function does return a value, but the compiler cannot tell that in the absence of a return statement. You can use #pragma warning to disable the generation of this warning.


Using and Preserving Registers in Inline Assembly

Home | Overview | How Do I

In general, you should not assume that a register will have a given value when an __asm block begins. Register values are not guaranteed to be preserved across separate __asm blocks. If you end a block of inline code and begin another, you cannot rely on the registers in the second block to retain their values from the first block. An __asm block inherits whatever register values result from the normal flow of control.

If you use the __fastcall calling convention, the compiler passes function arguments in registers instead of on the stack. This can create problems in functions with __asm blocks because a function has no way to tell which parameter is in which register. If the function happens to receive a parameter in EAX and immediately stores something else in EAX, the original parameter is lost. In addition, you must preserve the ECX register in any function declared with __fastcall.

To avoid such register conflicts, don’t use the __fastcall convention for functions that contain an __asm block. If you specify the __fastcall convention globally with the /Gr compiler option, declare every function containing an __asm block with __cdecl or __stdcall. (The __cdecl attribute tells the compiler to use the C calling convention for that function.) If you are not compiling with /Gr, avoid declaring the function with the __fastcall attribute.

When using __asm to write assembly language in C/C++ functions, you don't need to preserve the EAX, EBX, ECX, EDX, ESI, or EDI registers. For example, in the POWER2.C example in Writing Functions with Inline Assembly, the power2 function doesn't preserve the value in the EAX register. However, using these registers will affect code quality because the register allocator cannot use them to store values across __asm blocks. In addition, by using EBX, ESI or EDI in inline assembly code, you force the compiler to save and restore those registers in the function prologue and epilogue.

You should preserve other registers you use (such as DS, SS, SP, BP, and flags registers) for the scope of the __asm block. You should preserve the ESP and EBP registers unless you have some reason to change them (to switch stacks, for example). Also see Optimizing Inline Assembly.

Note If your inline assembly code changes the direction flag using the STD or CLD instructions, you must restore the flag to its original value.


Jumping to Labels in Inline Assembly

Home | Overview | How Do I

Like an ordinary C or C++ label, a label in an __asm block has scope throughout the function in which it is defined (not only in the block). Both assembly instructions and goto statements can jump to labels inside or outside the __asm block.

Labels defined in __asm blocks are not case sensitive; both goto statements and assembly instructions can refer to those labels without regard to case. C and C++ labels are case sensitive only when used by goto statements. Assembly instructions can jump to a C or C++ label without regard to case.

The following code shows all the permutations:

void func( void )
{
   goto C_Dest;  /* Legal: correct case   */
   goto c_dest;  /* Error: incorrect case */

   goto A_Dest;  /* Legal: correct case   */
   goto a_dest;  /* Legal: incorrect case */

   __asm
   {
      jmp C_Dest ; Legal: correct case
      jmp c_dest ; Legal: incorrect case

      jmp A_Dest ; Legal: correct case
      jmp a_dest ; Legal: incorrect case

      a_dest:    ; __asm label
   }

   C_Dest:       /* C label */
   return;
}

Don’t use C library function names as labels in __asm blocks. For instance, you might be tempted to use exit as a label, as follows:

; BAD TECHNIQUE: using library function name as label
jne exit
   .
   .
   .
exit:
   ; More __asm code follows

Because exit is the name of a C library function, this code might cause a jump to the exit function instead of to the desired location.

As in MASM programs, the dollar symbol ($) serves as the current location counter. It is a label for the instruction currently being assembled. In __asm blocks, its main use is to make long conditional jumps:

jne $+5 ; next instruction is 5 bytes long
jmp farlabel
; $+5
   .
   .
   .
farlabel:


Calling C Functions in Inline Assembly

Home | Overview | How Do I

An __asm block can call C functions, including C library routines. The following example calls the printf library routine:

#include <stdio.h>

char format[] = "%s %s\n";
char hello[] = "Hello";
char world[] = "world";
void main( void )
{
   __asm
   {
      mov  eax, offset world
      push eax
      mov  eax, offset hello
      push eax
      mov  eax, offset format
      push eax
      call printf
      //clean up the stack so that main can exit cleanly
      //use the unused register ebx to do the cleanup
      pop  ebx
      pop  ebx
      pop  ebx
   }
}

Because function arguments are passed on the stack, you simply push the needed arguments—string pointers, in the previous example—before calling the function. The arguments are pushed in reverse order, so they come off the stack in the desired order. To emulate the C statement

printf( format, hello, world );

the example pushes pointers to world, hello, and format, in that order, and then calls printf.


Calling C++ Functions in Inline Assembly

Home | Overview | How Do I

An __asm block can call only global C++ functions that are not overloaded. If you call an overloaded global C++ function or a C++ member function, the compiler issues an error.

You can also call any functions declared with extern "C" linkage. This allows an __asm block within a C++ program to call the C library functions, because all the standard header files declare the library functions to have extern "C" linkage.


Defining __asm Blocks as C Macros

Home | Overview | How Do I

C macros offer a convenient way to insert assembly code into your source code, but they demand extra care because a macro expands into a single logical line. To create trouble-free macros, follow these rules:

  • Enclose the __asm block in braces.

  • Put the __asm keyword in front of each assembly instruction.

  • Use old-style C comments ( /* comment */) instead of assembly-style comments ( ; comment) or single-line C comments ( // comment).

To illustrate, the following example defines a simple macro:

#define PORTIO __asm      \
/* Port output */         \
{                         \
   __asm mov al, 2        \
   __asm mov dx, 0xD007   \
   __asm out al, dx       \
}

At first glance, the last three __asm keywords seem superfluous. They are needed, however, because the macro expands into a single line:

__asm /* Port output */ { __asm mov al, 2  __asm mov dx, 0xD007 __asm out al, dx }

The third and fourth __asm keywords are needed as statement separators. The only statement separators recognized in __asm blocks are the newline character and __asm keyword. Because a block defined as a macro is one logical line, you must separate each instruction with __asm.

The braces are essential as well. If you omit them, the compiler can be confused by C or C++ statements on the same line to the right of the macro invocation. Without the closing brace, the compiler cannot tell where assembly code stops, and it sees C or C++ statements after the __asm block as assembly instructions.

Assembly-style comments that start with a semicolon (;) continue to the end of the line. This causes problems in macros because the compiler ignores everything after the comment, all the way to the end of the logical line. The same is true of single-line C or C++ comments ( // comment). To prevent errors, use old-style C comments ( /* comment */) in __asm blocks defined as macros.

An __asm block written as a C macro can take arguments. Unlike an ordinary C macro, however, an __asm macro cannot return a value. So you cannot use such macros in C or C++ expressions.

Be careful not to invoke macros of this type indiscriminately. For instance, invoking an assembly-language macro in a function declared with the __fastcall convention may cause unexpected results. (See Using and Preserving Registers in Inline Assembly.)


Optimizing Inline Assembly

Home | Overview | How Do I

The presence of an __asm block in a function affects optimization in several ways. First, the compiler doesn’t try to optimize the __asm block itself. What you write in assembly language is exactly what you get. Second, the presence of an __asm block affects register variable storage. The compiler avoids enregistering variables across an __asm block if the register’s contents would be changed by the __asm block. Finally, some other function-wide optimizations will be affected by the inclusion of assembly language in a function.


Automation Topics

Home | Overview | How Do I | Sample | Tutorial

Automation is available to both OLE and COM objects. For background, see the Overview. There are two categories of automation:

  • Automation (locally)

  • Remote Automation (over a network, using Distributed COM, or DCOM)

The remainder of this article concerns Automation. For Remote Automation, see the topic Remote Automation.

An Automation client is an application that can manipulate exposed objects belonging to another application. This is also called an Automation controller.

An Automation server is an application that exposes programmable objects to other applications. This is sometimes also called an “Automation component.”

The server application exposes Automation objects. These Automation objects have properties and methods as their external interface. Properties are named attributes of the Automation object. Properties are like the data members of a C++ class. Methods are functions that work on an Automation object. Methods are like the public member functions of a C++ class.

Note Properties can have member functions that access them. A Get/Set function pair typically accesses a property of the object.

Passing Parameters in Automation

One of the difficulties in creating Automation methods is providing a uniform “safe” mechanism to pass data between automation servers and clients. Automation uses the VARIANT type to pass data. The VARIANT type is a tagged union. It has a data member for the value (this is an anonymous C++ union) and a data member indicating the type of information stored in the union. The VARIANT type supports a number of standard data types: 2- and 4-byte integers, 4- and 8-byte floating point numbers, strings, and Boolean values. In addition, it supports the HRESULT (OLE error codes), CURRENCY (a fixed-point numeric type), and DATE (absolute date and time) types, as well as pointers to IUnknown and IDispatch interfaces.

The VARIANT type is encapsulated in the COleVariant class. The supporting CURRENCY and DATE classes are encapsulated in the COleCurrency and COleDateTime classes.

What do you want to know more about?

  • Automation Clients

  • Automation Servers

  • Remote Automation

  • OLE

  • Active Technology


Automation Clients

Home | Overview | How Do I | Sample | Tutorial

Automation makes it possible for your application to manipulate objects implemented in another application, or to expose objects so they can be manipulated. An automation client is an application that can manipulate exposed objects belonging to another application. The application that exposes the objects is called the Automation server. The client manipulates the server application’s objects by accessing those objects’ properties and functions.

There are two types of Automation clients:

  • Clients that dynamically (at run time) acquire information about the properties and operations of the server.

  • Clients that possess static information (provided at compile time) that specifies the properties and operations of the server.

Clients of the first kind acquire information about the server’s methods and properties by querying the OLE system’s IDispatch mechanism. Although it is adequate to use for dynamic clients, IDispatch is difficult to use for static clients, where the objects being driven must be known at compile time. For static bound clients, the Microsoft Foundation classes provide the COleDispatchDriver class along with ClassWizard support.

Static bound clients use a proxy class that is statically linked with the client application. This class provides a type-safe C++ encapsulation of the server application’s properties and operations.

The class COleDispatchDriver provides the principal support for the client side of Automation. Using ClassWizard, you create a class derived from COleDispatchDriver.

You then specify the type-library file describing the properties and functions of the server application’s object. ClassWizard reads this file and creates the COleDispatchDriver-derived class, with member functions that your application can call to access the server application’s objects in C++ in a type-safe manner. Additional functionality inherited from COleDispatchDriver simplifies the process of calling the proper Automation server.

What do you want to know more about?

  • Using Type Libraries

See Also The MFC AppWizard (EXE version): Step-by-Step, ClassWizard: Automation Support, ClassWizard: Adding Automation Properties and Methods


Automation Clients: Using Type Libraries

Home | Overview | How Do I | Sample | Tutorial

Automation clients must have information about server objects’ properties and methods if the clients are to manipulate the servers’ objects. Properties have data types; methods often return values and accept parameters. The client requires information about the data types of all of these in order to statically bind to the server object type.

This type information can be made known in several ways. The recommended way is to create a type library.

For information on Microsoft Object Description Language (ODL) and MkTypLib, see the OLE Programmer's Reference in the Win32 SDK.

ClassWizard can read a type-library file and create a dispatch class derived from COleDispatchDriver. An object of that class has properties and operations duplicating those of the server object. Your application calls this object’s properties and operations, and functionality inherited from COleDispatchDriver routes these calls to the OLE system, which in turn routes them to the server object.

ClassWizard automatically maintains this type-library file for you if you chose to include Automation when the project was created. As part of each build, the .tlb file will be built with MkTypLib.

To create a dispatch class from a type-library (.tlb) file

  1. In ClassWizard, click the Add Class button. The Add Class button appears on each tab of ClassWizard.

    The Add Class menu appears.

  2. On the Add Class menu, click From a type library.

    An Import from Type Library dialog box appears.

  3. In the Import from Type Library dialog box, select the .TLB file.

    Tip Some type library information is stored in files with .DLL, .OCX, or .OLB file extensions.

  4. Click OK.

    The Confirm Classes dialog box appears. The list contains the external names of the classes described in the type-library file. Other controls in the Confirm Classes dialog box show the proposed names for the dispatch classes and for the header and implementation files for those classes. As you select a class in the list box, the Class Name box shows the name for the corresponding class.

    You can use the Browse buttons to select other files, if you prefer to have the header and implementation information written in existing files or in a directory other than the project directory.

  5. In the Confirm Classes dialog box, edit the names of the new dispatch classes and their files.

  6. Click OK to close the Confirm Classes dialog box.

    The Type Library Tool writes header and implementation code for your dispatch class, using the class names and file names you have supplied, and adds the .CPP file to your project.

See Also ClassWizard: Adding Automation Properties and Methods


Automation Servers

Home | Overview | How Do I | Sample | Tutorial

Automation makes it possible for your application to manipulate objects implemented in another application, or to expose objects so they can be manipulated. An Automation server is an application that exposes programmable objects to other applications, which are called Automation clients. Exposing programmable objects enables clients to automate certain procedures by directly accessing the objects and functionality the server makes available.

Exposing objects this way is beneficial when applications provide functionality that is useful for other applications. For example, a word processor might expose its spell-checking functionality so that other programs can use it. Exposure of objects thus enables vendors to improve their applications’ functionality by using the ready-made functionality of other applications.

By exposing application functionality through a common, well-defined interface, Automation makes it possible to build applications in a single general programming language like Microsoft Visual Basic instead of in diverse, application-specific macro languages.

Support for Automation Servers

ClassWizard, AppWizard, and the framework all provide extensive support for Automation servers. They handle much of the overhead involved in making an Automation server, so you can focus your efforts on the functionality of your application.

The framework’s principal mechanism for supporting Automation is the dispatch map, a set of macros that expands into the declarations and calls needed to expose methods and properties for OLE. A typical dispatch map looks like this:

BEGIN_DISPATCH_MAP(CMyServerDoc, COleServerDoc)
    //{{AFX_DISPATCH_MAP(CMyServerDoc)
    DISP_PROPERTY(CMyServerDoc, "Msg", m_strMsg, VT_BSTR)
    DISP_FUNCTION(CMyServerDoc, "SetDirty", SetDirty, VT_EMPTY, VTS_I4)
    //}}AFX_DISPATCH_MAP
END_DISPATCH_MAP()

ClassWizard assists in maintaining dispatch maps. When you add a new method or property to a class, ClassWizard adds a corresponding DISP_FUNCTION or DISP_PROPERTY macro with parameters indicating the class name, external and internal names of the method or property, and data types.

ClassWizard also simplifies the declaration of Automation classes and the management of their properties and operations. When you use ClassWizard to add a class to your project, you specify its base class. If the base class allows Automation, ClassWizard displays controls you use to specify whether the new class should support Automation, whether it is “OLE Createable” (that is, whether objects of the class can be created on a request from a COM client), and the external name for the COM client to use.

ClassWizard then creates a class declaration, including the appropriate macros for the OLE features you have specified. ClassWizard also adds the skeleton code for implementation of your class’s member functions.

AppWizard simplifies the steps involved in getting your automation server application off the ground. If you select Automation support in AppWizard’s OLE Options page, AppWizard adds to your application’s InitInstance function the calls required to register your Automation objects and run your application as an Automation server.

What do you want to do?

  • Create an Automation server

  • Learn about Automation clients

  • Learn more about class CCmdTarget

  • Learn more about class COleDispatchDriver

See Also ClassWizard: Automation Support, The MFC AppWizard (EXE version): Step-by-Step


Automation Servers: Object-Lifetime Issues

Home | Overview | How Do I | Sample | Tutorial

When an Automation client creates or activates an OLE item, the server passes the client a pointer to that object. The client establishes a reference to the object through a call to the OLE function IUnknown::AddRef. This reference is in effect until the client calls IUnknown::Release. (Client applications written with the Microsoft Foundation Class Library’s OLE classes need not make these calls; the framework does so.) The OLE system and the server itself may establish references to the object. A server should not destroy an object as long as external references to the object remain in effect.

The framework maintains an internal count of the number of references to any server object derived from CCmdTarget. This count is updated when an Automation client or other entity adds or releases a reference to the object.

When the reference count becomes 0, the framework calls the virtual function CCmdTarget::OnFinalRelease. The default implementation of this function calls the delete operator to delete this object.

The Microsoft Foundation Class Library provides additional facilities for controlling application behavior when external clients have references to the application’s objects. Besides maintaining a count of references to each object, servers maintain a global count of active objects. The global functions AfxOleLockApp and AfxOleUnlockApp update the application’s count of active objects. If this count is nonzero, the application does not terminate when the user chooses Close from the system menu or Exit from the File menu. Instead, the application’s main window is hidden (but not destroyed) until all pending client requests have been completed. Typically, AfxOleLockApp and AfxOleUnlockApp are called in the constructors and destructors, respectively, of classes that support Automation.

Sometimes circumstances force the server to terminate while a client still has a reference to an object. For example, a resource on which the server depends may become unavailable, causing the server to encounter an error. Or the user may close a server document that contains objects to which other applications have references.

In the OLE Programmer’s Reference, see IUnknown::AddRef, IUnknown::Release.

See Also AfxOleCanExitApp


Remote Automation

Home | Overview | How Do I | Sample

A key feature of Visual C++ Enterprise Edition is remote automation.

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Remote Automation is a type of Automation that allows an interface consumer to execute an interface provider that resides on another machine, for example, on a network.

This article explains how to create Automation objects that can be invoked and executed remotely, and how to create Automation controllers that can use these remote automation objects. It also examines configuration options and points out the major differences between remote automation and DCOM (the distributed version of COM and OLE that allows interfaces other than those related to automation to be invoked and executed remotely).

What do you want to know more about?

  • History of DCOM (Distributed Component Object Model)

  • Where Does Remote Automation Fit In?

  • What Does Remote Automation Provide?

  • Remote Automation Security

  • Threading Models

  • Installation

  • The Automation Manager
    • The Remote Automation Connection Manager

    • Remote Automation User Components
  • How To Create Programs in Visual C++ Enterprise Edition That Use Remote Automation

  • The AUTOCLIK Sample


Remote Automation: History of DCOM

Home | Overview | How Do I | Sample

When Automation was first introduced in early 1993, it was capable of being used only between applications running on the same machine. However, as it shared the same underpinnings as the rest of OLE, that is, COM (or Component Object Model), it was always intended that it would become ‘remotable’ when COM itself was updated to include remoting capabilities. It was also planned that the transition from purely local operation to distributed operation would require little or no change to existing code.

So what does "remoting" mean? Local COM dictated that the consumer of an interface reside and execute on the same machine as the provider of that interface. For example, Microsoft Visual Basic could control a copy of Microsoft Excel on your desktop machine, but it was not capable of directing the execution of Excel on another machine. With the development of distributed COM, the consumer of an interface no longer needs to reside on the same machine as that on which the interface provider executes.

Once COM was adapted to work across a network, then any interface that was not tied to a local execution model (some interfaces have inherent reliance on local machine facilities, such as those drawing interfaces whose methods have handles to device contexts as parameters) would have the capability of being distributed: An interface consumer would make a request for a given interface; that interface may be provided by an instance of an object running (or to be run) on a different machine. The distribution mechanism inside COM would connect the consumer to the provider in such a way that method calls made by the consumer would appear at the provider end, where they would be executed. Any return values would then be sent back to the consumer. To all intents and purposes, the act of distribution is transparent to both the consumer and the provider.

Such a variety of COM does now exist. DCOM (for ‘distributed COM’), is shipped with versions of Windows NT beginning with version 4.0. Since late 1996, it has also been available for Windows 95 and its derivatives. In both cases, DCOM comprises a set of replacement and additional DLLs, with some utilities, which provide both local and remote COM capabilities. It is therefore now an inherent part of Win32-based platforms, and will be made available on other platforms by other organizations over time.

What do you want to know more about?

  • Where does remote automation fit in?

  • What does remote automation provide?


Where Does Remote Automation Fit In?

Home | Overview | How Do I | Sample

DCOM was released 1996, and is available with 32-bit platforms only. The Visual Basic team at Microsoft has always seen Visual Basic as using Automation to allow its components to communicate. The lack of a distributed version severely limited the use of these capabilities in enterprise environments, so the team developing Visual Basic 4.0 Enterprise Edition decided to investigate the creation of its own set of remoting components for the Automation parts of OLE and COM. Clearly, a major goal was to ensure that the result would be compatible with, and could be replaced by, DCOM when it became available. They then proceeded to implement Remote Automation (RA) for both 16-bit and 32-bit Windows platforms.

Remote Automation is not tied to any specific language, but until the release of Visual C++ 4.2 Enterprise Edition, it was shipped only with Visual Basic 4.0. Be aware that Remote Automation is wholly subsumed by DCOM. If you have the opportunity to use DCOM instead of Remote Automation in your applications, you should do so. Nevertheless, there are scenarios where Remote Automation is more appropriate at present:

  • Wherever you have 16-bit clients

  • If your organization has not rolled out a DCOM-enabled version of Windows NT or Windows 95 yet

  • If you are upgrading an existing application suite that uses Remote Automation to use C++ components in place of one or more VB components

There need be no difference between programs created to use Remote Automation and those created to use Automation over DCOM, and the configuration utilities make it very simple to switch operation between Remote Automation and DCOM. Consequently, it is not difficult to upgrade an application from Remote Automation to DCOM once the infrastructure is in place.

What do you want to know more about?

  • What does Remote Automation provide?


What Does Remote Automation Provide?

Home | Overview | How Do I | Sample

Remote Automation allows programs to invoke IDispatch implementations on one machine from another. It also supports other interfaces required by Automation, specifically IEnumVARIANT for collection support. It does not provide the ability to distribute any other COM interface (except IUnknown, of course) and, like regular Automation, it contains marshaling support only for those data types supported by Automation.

This set of facilities allows a program to access the methods and properties, including those that return collections or further automation objects, of an object running on an accessible network node. If the client machine is also running the appropriate software, it is possible for the server to call back to the client, again using Automation facilities (this works for 32-bit clients only, and is conceptually similar to events, although it does not use the same mechanism).

In order for an application to be operable as a Remote Automation server, it must be implemented as an executable (that is, as a "local server" (ironically!) rather than as an "inproc server").

What do you want to know more about?

  • Where does remote automation fit in?


Remote Automation: Security

Home | Overview | How Do I | Sample

Remote Automation supports a basic level of security to allow a server application writer (or, rather, its administrator) to specify how a specific object may be activated remotely. All automation objects on a given system may be globally set to "disallow remote activation" or to "allow remote activation". Additionally, and more often, individual objects may be given such capabilities. Remote Automation uses a key in each object's registry settings, AllowRemoteActivation, to determine whether a given server may be activated remotely. If the system-wide settings use this mode, then each object in the registry may be assigned this key, and the individual status of each one may be set to "yes" or "no" as appropriate.

If the server system is running Windows NT, then an alternative form of security is allowed. In this case, Remote Automation uses the NT ACL (access control list) to specify which users or group(s) of users may remotely activate a given server.

Note that the security options apply to the whole object; it is not possible to set attributes of a specific interface, or of individual properties or methods on that object.

All security options may be set through the Remote Automation Connection Manager (commonly referred to as the RAC Manager).


Remote Automation: Threading Models

Home | Overview | How Do I | Sample

Remote Automation supports both the single-threaded and the apartment-threaded models of COM. On 32-bit platforms (which is all that Visual C++ supports), the threading model should be set to "apartment". For more information on how and where to do this, see Remote Automation: Creating Programs That Use Remote Automation.


Remote Automation: Installation

Home | Overview | How Do I | Sample

Remote Automation has relatively few components:

  • The Remote Automation client proxy, AUTPRX32.DLL.

  • The Remote Automation server-side component, the Automation Manager, AUTMGR32.EXE.

  • The RAC Manager, RACMGR32.EXE, with its matching RACREG32.DLL.

Of these, RAC Manager is written in Visual Basic and therefore needs the Visual Basic run-time support, too. These and the other Remote Automation files are installed by Setup when you install Visual C++ Version Enterprise Edition.

If you copy the Remote Automation components to a computer on which Visual C++ version Enterprise Edition is not installed, ensure that REGSRV32.EXE is on the computer’s path, and register RACREG32.DLL using the following command line:

REGSRVR32 RACREG32.DLL

Note Versions of RAC Manager prior to Visual C++ 5.0 required GUAGE32.OCX and TABCTL32.OCX. Neither of these are required for the version of RAC Manager that ships with Visual C++ Enterprise Edition, version 5.0 or later.

What do you want to know more about?

  • The Automation Manager

  • The Remote Automation Connection Manager

  • Remote Automation user components


The Automation Manager

Home | Overview | How Do I | Sample

AUTMGR32.EXE should be copied to the Windows system directory of each machine that is intending to provide Remote Automation objects. For Windows 95, this directory is typically C:\WINDOWS\SYSTEM. For Windows NT, it is typically C:\WINDOWS\SYSTEM32.

If you want to enable callbacks from the server to the client, this executable file should also be copied to the system directory of each client machine.

When the Automation Manager is running, it displays a small window on the server machine that contains brief status information. If you would like to hide it, please refer to article Q138067 in the Microsoft Knowledge Base.

What do you want to know more about?

  • The Remote Automation Connection Manager

  • Remote Automation user components


The Remote Automation Connection Manager

Home | Overview | How Do I | Sample

To configure both client and server machines, you need to make registry changes. Rather than doing this by hand, it is far easier to use the Remote Automation Connection Manager (RAC Manager) tool. This tool, RACMGR32.EXE, along with RACREG32.DLL, needs to be copied to any directory you choose. By putting it in the PATH, it can be executed from the task bar using Run. Alternatively, you can create a shortcut to it or place a reference to it on the Start menu.

RACMGR32 is written in Visual Basic and therefore needs some Visual Basic support DLLs. These files may be found in the same directory on the CD; for more information, see Remote Automation Components. The versions of these files that are installed by the Setup for Visual C++ Enterprise Edition are equivalent or more recent than those that shipped with Visual Basic Enterprise Edition 5.0. The Visual C++ Setup copies the new versions of the Visual Basic files to your system directory. For Windows 95, this directory is typically C:\Windows\System. For Windows NT, it is typically C:\Windows\System32. Setup also registers these files with the operating system. You may remove them from your Visual Basic installation if you wish.

What do you want to know more about?

  • The Automation Manager

  • Remote Automation user components


Remote Automation User Components

Home | Overview | How Do I | Sample

You will need to ensure that each client machine contains your client program and any support DLLs it requires. You will also need to ensure that the server application, and any support DLLs it requires, are present on the server machine. Finally, you will need to ensure that your server program is registered on each client machine before RAC Manager can be run to configure the connection. If the program is self-registering (as most will be), you need only execute the server program on the client machine to register it. Failing that, you may have to execute a registration file that you provide, or manually edit the registry.

What do you want to know more about?

  • The Automation Manager

  • The Remote Automation Connection Manager


Remote Automation: Creating Programs That Use Remote Automation

Home | Overview | How Do I | Sample

Any automation object, and any automation controller, is able to use Remote Automation without any change to the source code, without the need for recompilation, and without the need for relinking. Once you have a setup that works locally (that is, on the same machine), you need go through only a few steps to execute it remotely.

To execute the Remote Automation object

  1. Register the application on the client machine(s).

  2. Configure the client access to use remote server.

  3. Install and register the application on the server machine(s).

  4. Configure the server to allow remote activation.

  5. Install the Automation Manager on the server machine(s).

  6. Run Automation Manager on the server(s).

  7. Run the application on the client(s).

Step 1 is most easily accomplished by loading and executing the server application on the client machine, as most servers are self-registering. If you tested the setup locally beforehand, this stage is already complete. If the server application is not self-registering, you may want to make it so. Otherwise, you will need to provide a registration file that the local user can run to perform this step. If you do neither of these things, you or an administrator will need to edit the registry manually, a procedure which is not recommended for all but the most advanced users.

Step 2 involves the use of the Remote Automation Connection (RAC) Manager. Run RAC Manager and ensure that the server connection tab is uppermost. Next, find the entry for the server object in the OLE Classes pane and click on it. Then move to the Network Address combo box and enter the name of the server machine on which the remote executable file will be run. For example, you may enter \\MyServer here. Then choose the appropriate network protocol from the list provided. You may need to check with your network administrator to determine which protocol is recommended. In many cases, this will be TCP/IP. Finally, you may want to choose an authentication level. In most cases, this will be left as (None) or Default. Now right-click on the server in the OLE Classes pane. This will produce a context menu from which you can select local or remote operation. Select remote.

Step 3 involves properly installing and registering the server application on the selected server machine(s). Again, if the application is self-registering, executing it once will also register it.

Step 4 involves configuring the server to allow remote execution. Run RAC Manager on the server machine, and ensure that the Client Access tab has the focus. Choose the activation model that you want (typically Allow Remote Creates by Key. If you do choose this option, you also need to click the Allow Remote Activation checkbox to set the value of the registry entry to ‘Y’). If you are running Windows NT, and you choose the Allow Remote Creates (ACL) option, you also have the option to edit the ACL by pushing the Edit ACL button.

To allow Remote Automation to work, you then need to ensure that the Automation Manager is installed and running on the server machine(s). If it is not installed, copy AUTMGR32.EXE to the Windows system directory. For information on how to do so, see Remote_ Automation.3a_.Installation. To start Remote Automation , execute the Automation Manager. It will display a small status window in which a number of messages will be shown. Once it has started, it will minimize itself. If you want to continue to see status information, you can click the Automation Manager tab in the task bar to restore the window.

The final step is to execute the client application on the client machine. If you have followed the steps above, it should connect to the server object and execute precisely as it did locally, albeit a little slower.

Notice that the RAC Manager also allows you to switch between Remote Automation and distributed COM (DCOM, on those platforms that support DCOM) with a single click of a radio button. If you choose DCOM, there are various other configuration options you can set. See the DCOM documentation for further details.

See Also Remote Automation: The AUTOCLIK Sample


Remote Automation: The AUTOCLIK Sample

Home | Overview | How Do I | Sample

AUTOCLIK is a simple Automation server application that you can use as a base from which to learn more about Remote Automation.

To install the AUTOCLIK project onto your development machine

  1. Select Search from the Help menu. The MSDN Library browser appears.

  2. Type “AUTOCLIK” in the edit box of the Index tab.

  3. Double-click “AUTOCLIK sample” in the list of index entries, or select “AUTOCLIK sample” and click the Display button.

  4. The topic "AUTOCLIK: Automation Server Application" appears in the MSDN Library browser's main window.

  5. Click STEP3 to install the AUTOCLIK project.

To install AUTOCLIK.EXE on two machines and drive it using Remote Automation

  1. Build the Step 3 version of AUTOCLIK.EXE.

  2. Run AUTOCLIK.EXE in standalone fashion and then shut it down. This will register it as an Automation server.

  3. Copy AUTOCLIK.EXE to a remote machine, run it there, and then shut it down.

  4. Build AUTODRIV.EXE and verify that running it starts AUTOCLIK.EXE on the local machine. Read the AutoClik Tutorial to find out more about AUTODRIV.EXE.

  5. On the remote machine, start AUTMGR32.EXE (Automation Manager).

  6. On the remote machine, start RACMGR32.EXE (Remote Automation Connection Manager).

  7. In the Remote Automation Connection Manager, select AutoClik.Document from the OLE Classes list.

  8. Choose a system security policy from the Client Access tab to grant client access to AutoClik.Document.

  9. On the local machine, start RACMGR32.EXE and select AutoClik.Document from the OLE Classes list.

  10. From the Server Connection tab, choose both the network address of the remote machine and the appropriate network protocol.

  11. With AutoClik.Document still selected in the OLE Classes listbox, choose the Remote command from the Register menu.

  12. On the local machine, run AUTODRIV.EXE or the equivalent AUTOCLIK.MAK Visual Basic project if you want to have a Visual Basic, rather than an MFC, client.

On the remote machine, you should now be able to see AUTOCLIK executing commands initiated from the local client.


Calling Conventions Topics

Home | Overview | How Do I

Visual C++ supports several different conventions for calling functions. Using the information in this family of articles will help you debug your program and successfully link your code with assembly-language routines.

What do you want to know more about?

  • Argument Passing and Naming Conventions (__cdecl, __stdcall, __fastcall, and others)

  • Calling Example: Function Prototype and Call

  • Naked Function Calls

  • Naked Function Example

  • Floating Point Coprocessor and Calling Conventions


Argument Passing and Naming Conventions

Home | Overview | How Do I

All arguments are widened to 32 bits when they are passed. Return values are also widened to 32 bits and returned in the EAX register, except for 8-byte structures, which are returned in the EDX:EAX register pair. Larger structures are returned in the EAX register as pointers to hidden return structures. Parameters are pushed onto the stack from right to left.

The compiler generates prolog and epilog code to save and restore the ESI, EDI, EBX, and EBP registers, if they are used in the function.

Note For information on how to define your own function prolog and epilog code, see Naked Function Calls.

The following calling conventions are supported by the Visual C/C++ compiler.

Keyword | Stack cleanup | Parameter passing
__cdecl | Caller | Pushes parameters on the stack, in reverse order (right to left)
__stdcall | Callee | Pushes parameters on the stack, in reverse order (right to left)
__fastcall | Callee | Stored in registers, then pushed on stack
thiscall (not a keyword) | Callee | Pushed on stack; this pointer stored in ECX

For related information, see Obsolete Calling Conventions.


__cdecl

Home | Overview | How Do I

Microsoft Specific —>

This is the default calling convention for C and C++ programs. Because the stack is cleaned up by the caller, it can do vararg functions. The __cdecl calling convention creates larger executables than __stdcall, because it requires each function call to include stack cleanup code. The following list shows the implementation of this calling convention.

Element | Implementation
Argument-passing order | Right to left
Stack-maintenance responsibility | Calling function pops the arguments from the stack
Name-decoration convention | Underscore character (_) is prefixed to names
Case-translation convention | No case translation performed

Note For related information, see Decorated Names.

Place the __cdecl modifier before a variable or a function name. Because the C naming and calling conventions are the default, the only time you need to use __cdecl is when you have specified the /Gz (stdcall) or /Gr (fastcall) compiler option. The /Gd compiler option forces the __cdecl calling convention.

Example

In the following example, the compiler is instructed to use C naming and calling conventions for the system function:

// Example of the __cdecl keyword
_CRTIMP int __cdecl system(const char *);

END Microsoft Specific


__stdcall

Home | Overview | How Do I

Microsoft Specific —>

The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl. Functions that use this calling convention require a function prototype. The following list shows the implementation of this calling convention.

Element | Implementation
Argument-passing order | Right to left.
Argument-passing convention | By value, unless a pointer or reference type is passed.
Stack-maintenance responsibility | Called function pops its own arguments from the stack.
Name-decoration convention | An underscore (_) is prefixed to the name. The name is followed by the at sign (@) followed by the number of bytes (in decimal) in the argument list. Therefore, the function declared as int func( int a, double b ) is decorated as follows: _func@12
Case-translation convention | None

The /Gz compiler option specifies __stdcall for all functions not explicitly declared with a different calling convention.

Functions declared using the __stdcall modifier return values the same way as functions declared using __cdecl.

END Microsoft Specific

Example

In the following example, use of __stdcall results in all WINAPI function types being handled as a standard call:

// Example of the __stdcall keyword
#define WINAPI __stdcall


__fastcall

Home | Overview | How Do I

Microsoft Specific —>

The __fastcall calling convention specifies that arguments to functions are to be passed in registers, when possible. The following list shows the implementation of this calling convention.

Element | Implementation
Argument-passing order | The first two DWORD or smaller arguments are passed in ECX and EDX registers; all other arguments are passed right to left.
Stack-maintenance responsibility | Called function pops the arguments from the stack.
Name-decoration convention | At sign (@) is prefixed to names; an at sign followed by the number of bytes (in decimal) in the parameter list is suffixed to names.
Case-translation convention | No case translation performed.

Note Future compiler versions may use different registers to store parameters.

Using the /Gr compiler option causes each function in the module to compile as fastcall unless the function is declared with a conflicting attribute, or the name of the function is main.

END Microsoft Specific

Example

In the following example, the function named DeleteAggrWrapper is passed arguments in registers:

// Example of the __fastcall keyword
#define FASTCALL    __fastcall

void FASTCALL DeleteAggrWrapper(void* pWrapper);


thiscall

Home | Overview | How Do I

This is the default calling convention used by C++ member functions that do not use variable arguments. The callee cleans the stack, so the compiler makes vararg functions __cdecl, and pushes the this pointer on the stack last. The thiscall calling convention cannot be explicitly specified in a program, because thiscall is not a keyword.

All function arguments are pushed on the stack. Because this calling convention applies only to C++, there is no C name decoration scheme.


Obsolete Calling Conventions

Home | Overview | How Do I

The __pascal, __fortran, and __syscall calling conventions are no longer supported. You can emulate their functionality by using one of the supported calling conventions and appropriate linker options.

WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.


Calling Example: Function Prototype and Call

Home | Overview | How Do I

The following example shows the results of making a function call using various calling conventions.

This example is based on the following function skeleton. Replace calltype with the appropriate calling convention.

void    calltype MyFunc( char c, short s, int i, double f );
.
.
.
void    MyFunc( char c, short s, int i, double f )
    {
    .
    .
    .
    }
.
.
.
MyFunc ('x', 12, 8192, 2.7183);

See Results of Calling Example.


Results of Calling Example

Home | Overview | How Do I

__cdecl

The C decorated function name is “_MyFunc.”

The__cdecl calling convention

__stdcall and thiscall

The C decorated name (__stdcall) is “_MyFunc@20.” The C++ decorated name is proprietary.

The __stdcall and thiscall calling conventions

__fastcall

The C decorated name (__fastcall) is “@MyFunc@20.” The C++ decorated name is proprietary.

The__fastcall calling convention

Return to Calling Example: Function Prototype and Call.


Naked Function Calls

Home | Overview | How Do I

Functions declared with the naked attribute are emitted without prolog or epilog code, enabling you to write your own custom prolog/epilog sequences using inline assembler. Naked functions are provided as an advanced feature. They enable you to declare a function that is being called from a context other than C/C++, and thus make different assumptions about where parameters are, or which registers are preserved. Examples include routines such as MS-DOS interrupt handlers. This feature is particularly useful for writers of virtual device drivers (VxDs). See Naked Function Example.

What do you want to know more about?

  • Syntax of Naked Function Calls

  • Rules and Limitations for Naked Functions


Syntax of Naked Function Calls

Home | Overview | How Do I

Because the naked attribute is not a type modifier, naked functions use the extended attribute syntax. For example, the following code defines a function with the naked attribute:

__declspec( naked ) int func( formal_parameters )
{
    // Function body
}

Or, alternatively:

#define Naked   __declspec( naked )
Naked int func( formal_parameters )
{
    // Function body
}

The naked modifier affects only the nature of the compiler’s code generation for the function’s prolog and epilog sequences. It does not affect the code that is generated for calling such functions. Thus, the naked attribute is not considered part of the function’s type. As such, function pointers cannot have the naked attribute. Furthermore, the naked attribute has no meaning when applied to a data definition. Any attempt to apply it to a data definition will generate a compiler error. For example, the following code samples will generate errors:

__declspec( naked ) int i;  // Error--naked attribute not permitted on
                            // data declarations.

extern __declspec( naked ) int i;   // Error--naked attribute not
                                    // permitted on data declarations.

The naked attribute is relevant only to the definition of the function. Thus it cannot be specified on the function’s prototype. The following declaration will generate a compiler error:

__declspec( naked ) int func();  // Error--naked attribute not permitted
                                 // on function declarations.

The compiler provides a new symbolic argument for use in the inline assembler block of function prolog code. This symbol, __LOCAL_SIZE, is used to allocate space for local variables on the stack frame in your custom prolog code. This constant contains a value determined by the compiler, and it represents the number of bytes of local variables.

__LOCAL_SIZE includes all user-defined local variables as well as compiler-generated temporary variables. __LOCAL_SIZE may be used as an immediate operand or in an expression. For example:

mov     eax, __LOCAL_SIZE           /* Immediate operand */
mov     eax, __LOCAL_SIZE + 4       /* Expression */
mov     eax, [ebp - __LOCAL_SIZE]   /* Expression */


Rules and Limitations for Naked Functions

Home | Overview | How Do I

The following rules and limitations apply to naked functions:

  • The return statement is not permitted.

  • Structured Exception Handling constructs are not permitted because they must unwind across the stack frame.

  • For the same reason, any form of setjmp is prohibited.

  • Use of the _alloca function is prohibited.

  • To ensure that no initialization code for local variables appears before the prolog sequence, initialized local variables are not permitted at function scope. In particular, the declaration of C++ objects is not permitted at function scope. There may, however, be initialized data in a nested scope.

  • Frame pointer optimization (the /Oy compiler option) is not recommended, but it is automatically suppressed for a naked function.

  • You cannot declare C++ class objects at the function lexical scope. You can, however, declare objects in a nested block.


Naked Function Example

Home | Overview | How Do I

The following is a minimal example of a naked function containing custom prolog and epilog sequences:

__declspec ( naked ) func()
{
    int i;
    int j;

    _asm
        {
        push   ebp
        mov     ebp, esp
        sub     esp, __LOCAL_SIZE
        }

    /* C and/or _asm code */

    _asm
        {
        mov     esp, ebp
        pop     ebp
        ret
        }
}


Floating Point Coprocessor and Calling Conventions

Home | Overview | How Do I

If you are writing assembly routines for the floating point coprocessor, you must preserve the floating point control word and clean the coprocessor stack unless you are returning a float or double value (which your function should return in ST(0)).


CObject Class Topics

Home | Overview | How Do I | FAQ

CObject is the root base class for most of the Microsoft Foundation Class Library (MFC). The CObject class contains many useful features that you may want to incorporate into your own program objects, including serialization support, run-time class information, and object diagnostic output. If you derive your class from CObject, your class can exploit these CObject features.

Frequently Asked Questions About CObject

  • Do I have to derive new classes from CObject?

  • What does it cost me to derive a class from CObject?

What do you want to do?

  • Derive a class of my own from CObject

  • Add support for run-time class information, dynamic creation, and serialization to my derived class

  • Access information about my class at run time

  • Create objects of my class dynamically

See Also Files in MFC, Serialization (Object Persistence)


CObject Class: Deriving a Class from CObject

Home | Overview | How Do I | FAQ

This article describes the minimum steps necessary to derive a class from CObject. Other CObject class articles describe the steps needed to take advantage of specific CObject features, such as serialization and diagnostic debugging support.

In the discussions of CObject, the terms “interface file” and “implementation file” are used frequently. The interface file (often called the header file, or .H file) contains the class declaration and any other information needed to use the class. The implementation file (or .CPP file) contains the class definition as well as the code that implements the class member functions. For example, for a class named CPerson, you would typically create an interface file named PERSON.H and an implementation file named PERSON.CPP. However, for some small classes that will not be shared among applications, it is sometimes easier to combine the interface and implementation into a single .CPP file.

You can choose from four levels of functionality when deriving a class from CObject:

  • Basic functionality: No support for run-time class information or serialization but includes diagnostic memory management.

  • Basic functionality plus support for run-time class information.

  • Basic functionality plus support for run-time class information and dynamic creation.

  • Basic functionality plus support for run-time class information, dynamic creation, and serialization.

Classes designed for reuse (those that will later serve as base classes) should at least include run-time class support and serialization support, if any future serialization need is anticipated.

You choose the level of functionality by using specific declaration and implementation macros in the declaration and implementation of the classes you derive from CObject.

The following table shows the relationship among the macros used to support serialization and run-time information.

Macros Used for Serialization and Run-Time Information

Macro used
CObject::IsKindOf 		CRuntimeClass::
CreateObject 		CArchive::operator>>
CArchive::operator<<
Basic CObject functionality | No | No | No
DECLARE_DYNAMIC | Yes | No | No
DECLARE_DYNCREATE | Yes | Yes | No
DECLARE_SERIAL | Yes | Yes | Yes

To use basic CObject functionality

  • Use the normal C++ syntax to derive your class from CObject (or from a class derived from CObject).

    The following example shows the simplest case, the derivation of a class from CObject:

    class CPerson : public CObject
{
    // add CPerson-specific members and functions...
}

Normally, however, you may want to override some of CObject’s member functions to handle the specifics of your new class. For example, you may usually want to override the Dump function of CObject to provide debugging output for the contents of your class. For details on how to override Dump, see the article Diagnostics: Dumping Object Contents. You may also want to override the AssertValid function of CObject to provide customized testing to validate the consistency of the data members of class objects. For a description of how to override AssertValid, see Overriding the AssertValid Function in the article Diagnostics: Checking Object Validity.

The article CObject Class: Specifying Levels of Functionality describes how to specify other levels of functionality, including run-time class information, dynamic object creation, and serialization.


CObject Class: Specifying Levels of Functionality

Home | Overview | How Do I | FAQ

This article describes how to add the following levels of functionality to your CObject-derived class:

  • Run-time class information

  • Dynamic creation support

  • Serialization support

For a general description of CObject functionality, see the article CObject Class: Deriving a Class from CObject.

To add run-time class information

CObject supports run-time class information through the IsKindOf function, which allows you to determine if an object belongs to or is derived from a specified class. For more detailed information, see the articles Files in MFC and Serialization (Object Persistence). This capability is not supported directly by the C++ language. The IsKindOf function permits you to do a type-safe cast down to a derived class.

Use the following steps to access run-time class information:

  1. Derive your class from CObject, as described in the CObject Class: Deriving a Class from CObject article.

  2. Use the DECLARE_DYNAMIC macro in your class declaration, as shown here:
    class CPerson : public CObject
{
    DECLARE_DYNAMIC( CPerson )

    // rest of class declaration follows...
};
  3. Use the IMPLEMENT_DYNAMIC macro in the implementation file (.CPP) of your class. This macro takes as arguments the name of the class and its base class, as follows:
    IMPLEMENT_DYNAMIC( CPerson, CObject )

Note Always put IMPLEMENT_DYNAMIC in the implementation file (.CPP) for your class. The IMPLEMENT_DYNAMIC macro should be evaluated only once during a compilation and therefore should not be used in an interface file (.H) that could potentially be included in more than one file.

To add dynamic creation support

CObject also supports dynamic creation, which is the process of creating an object of a specific class at run time. The object is created by the CreateObject member function of CRuntimeClass. Your document, view, and frame class should support dynamic creation because the framework (through the CDocTemplate class) needs to create them dynamically. Dynamic creation is not supported directly by the C++ language. To add dynamic creation, you must do the following:

  1. Derive your class from CObject.

  2. Use the DECLARE_DYNCREATE macro in the class declaration.

  3. Define a constructor with no arguments (a default constructor).

  4. Use the IMPLEMENT_DYNCREATE macro in the class implementation file.

To add serialization support

“Serialization” is the process of writing or reading the contents of an object to and from a file. The Microsoft Foundation Class Library uses an object of the CArchive class as an intermediary between the object to be serialized and the storage medium. The CArchive object uses overloaded insertion (<<) and extraction (>>) operators to perform writing and reading operations.

The following steps are required to support serialization in your classes:

  1. Derive your class from CObject.

  2. Override the Serialize member function.

    Note If you call Serialize directly, that is, you do not want to serialize the object through a polymorphic pointer, omit steps 3 through 5.

  3. Use the DECLARE_SERIAL macro in the class declaration.

  4. Define a constructor with no arguments (a default constructor).

  5. Use the IMPLEMENT_SERIAL macro in the class implementation file.

Note A “polymorphic pointer” points to an object of a class (call it A) or to an object of any class derived from A (say, B). To serialize through a polymorphic pointer, the framework must determine the run-time class of the object it is serializing (B), since it might be an object of any class derived from some base class (A).

For more details on how to enable serialization when you derive your class from CObject, see the articles Files in MFC and Serialization (Object Persistence).


CObject Class: Accessing Run-Time Class Information

Home | Overview | How Do I | FAQ

This article explains how to access information about the class of an object at run time.

Note MFC does not use the Run-Time Type Information (RTTI) support introduced in Visual C++ 4.0.

If you have derived your class from CObject and used the DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC, the DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE, or the DECLARE_SERIAL and IMPLEMENT_SERIAL macros explained in the article CObject Class: Deriving a Class from CObject, the CObject class has the ability to determine the exact class of an object at run time.

This ability is most useful when extra type checking of function arguments is needed and when you must write special-purpose code based on the class of an object. However, this practice is not usually recommended because it duplicates the functionality of virtual functions.

The CObject member function IsKindOf can be used to determine if a particular object belongs to a specified class or if it is derived from a specific class. The argument to IsKindOf is a CRuntimeClass object, which you can get using the RUNTIME_CLASS macro with the name of the class.

To use the RUNTIME_CLASS macro

  • Use RUNTIME_CLASS with the name of the class, as shown here for the class CObject:
    CRuntimeClass* pClass = RUNTIME_CLASS( CObject );

You will rarely need to access the run-time class object directly. A more common use is to pass the run-time class object to the IsKindOf function, as shown in the next procedure. The IsKindOf function tests an object to see if it belongs to a particular class.

To use the IsKindOf function

  1. Make sure the class has run-time class support. That is, the class must have been derived directly or indirectly from CObject and used the DECLARE_DYNAMIC and IMPLEMENT_DYNAMIC, the DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE, or the DECLARE_SERIAL and IMPLEMENT_SERIAL macros explained in the article CObject Class: Deriving a Class from CObject.

  2. Call the IsKindOf member function for objects of that class, using the RUNTIME_CLASS macro to generate the CRuntimeClass argument, as shown here:
    // in .H file
class CPerson : public CObject
{
    DECLARE_DYNAMIC( CPerson )
public:
    CPerson(){};

    // other declaration
};

// in .CPP file
IMPLEMENT_DYNAMIC( CPerson, CObject )

void SomeFunction(void)
{
CObject* pMyObject = new CPerson;

if(pMyObject->IsKindOf( RUNTIME_CLASS( CPerson ) ) )
{
//if IsKindOf is true, then cast is all right
CPerson* pmyPerson = (CPerson*) pMyObject ;
...
delete pmyPerson;
}
...
delete [MyObject];
}

    Note IsKindOf returns TRUE if the object is a member of the specified class or of a class derived from the specified class. IsKindOf does not support multiple inheritance or virtual base classes, although you can use multiple inheritance for your derived Microsoft Foundation classes if necessary.

One use of run-time class information is in the dynamic creation of objects. This process is discussed in the article CObject Class: Dynamic Object Creation.

For more detailed information on serialization and run-time class information, see the articles Files in MFC and Serialization (Object Persistence).


CObject Class: Dynamic Object Creation

Home | Overview | How Do I | FAQ

This article explains how to create an object dynamically at run time. The procedure uses run-time class information, as discussed in the article CObject Class: Accessing Run-Time Class Information.

To dynamically create an object given its run-time class

  • Use the following code to dynamically create an object by using the CreateObject function of the CRuntimeClass. Note that on failure, CreateObject returns NULL instead of raising an exception:
    CRuntimeClass* pRuntimeClass = RUNTIME_CLASS( CMyClass );
CObject* pObject = pRuntimeClass->CreateObject();
ASSERT( pObject->IsKindOf( RUNTIME_CLASS( CMyClass ) ) );


Collections Topics

Home | Overview | How Do I | Sample | Tutorial

This group of articles explains the MFC collection classes.

The Microsoft Foundation Class Library provides collection classes to manage groups of objects. These classes are of two types:

  • Collection classes created from C++ templates

  • Collection classes not created from templates

Other topics covered in this article include:

  • Collection shapes

  • Further reading about collections

Tip The nontemplate collection classes have been provided by MFC beginning with MFC version 1.0. If your code already uses these classes, you can continue to use them. If you write new type-safe collection classes for your own data types, consider using the newer template-based classes.

Collection Shapes

A collection class is characterized by its “shape” and by the types of its elements. The shape refers to the way the objects are organized and stored by the collection. MFC provides three basic collection shapes: lists, arrays, and maps (also known as dictionaries). You can pick the collection shape most suited to your particular programming problem.

Each of the three provided collection shapes is described briefly below. the table Collections: Choosing a Collection Class compares the features of the shapes to help you decide which is best for your program.

  • List

    The list class provides an ordered, nonindexed list of elements, implemented as a doubly linked list. A list has a “head” and a “tail,” and adding or removing elements from the head or tail, or inserting or deleting elements in the middle, is very fast.

  • Array

    The array class provides a dynamically sized, ordered, and integer-indexed array of objects.

  • Map (also known as a dictionary)

    A map is a collection that associates a key object with a value object.

The Template-Based Collection Classes

The easiest way to implement a type-safe collection that contains objects of any type is to use one of the MFC template-based classes. For examples of these classes, see the MFC Advanced Concepts sample COLLECT.

The following table lists the MFC template-based collection classes.

Collection Template Classes

Collection contents | Arrays | Lists | Maps
Collections of objects of any type | CArray | CList | CMap
Collections of pointers to objects of any type | CTypedPtrArray | CTypedPtrList | CTypedPtrMap

The Collection Classes Not Based on Templates

If your application already uses MFC nontemplate classes, you can continue to use them, although for new collections you should consider using the template-based classes. The following table lists the MFC collection classes not based on templates.

Nontemplate Collection Classes

Arrays | Lists | Maps
CObArray | CObList | CMapPtrToWord
CByteArray | CPtrList | CMapPtrToPtr
CDWordArray | CStringList | CMapStringToOb
CPtrArray |  | CMapStringToPtr
CStringArray |  | CMapStringToString
CWordArray |  | CMapWordToOb
CUIntArray |  | CMapWordToPtr

The previous table in the article Collections: Choosing a Collection Class describes the MFC collection classes in terms of their characteristics (other than shape):

  • Whether the class uses C++ templates

  • Whether the elements stored in the collection can be serialized

  • Whether the elements stored in the collection can be dumped for diagnostics

  • Whether the collection is type-safe

Further Reading About Collections

The following articles describe how to use the collection classes to make type-safe collections and how to perform a number of other operations using collections:

  • Collections: Choosing a Collection Class

  • Collections: Template-Based Classes

  • Collections: How to Make a Type-Safe Collection

  • Collections: Accessing All Members of a Collection

  • Collections: Deleting All Objects in a CObject Collection

  • Collections: Creating Stack and Queue Collections


Collections: Choosing a Collection Class

Home | Overview | How Do I | Sample | Tutorial

This article contains detailed information designed to help you choose a collection class for your particular application needs.

Your choice of a collection class depends on a number of factors, including:

  • The features of the class shape: order, indexing, and performance, as shown in the Collection Shape Features table later in this topic

  • Whether the class uses C++ templates

  • Whether the elements stored in the collection can be serialized

  • Whether the elements stored in the collection can be dumped for diagnostics

  • Whether the collection is type-safe

The following table, Collection Shape Features, summarizes the characteristics of the available collection shapes.

  • Columns 2 and 3 describe each shape’s ordering and access characteristics. In the table, the term “ordered” means that the order in which items are inserted and deleted determines their order in the collection; it does not mean the items are sorted on their contents. The term “indexed” means that the items in the collection can be retrieved by an integer index, much like items in a typical array.

  • Columns 4 and 5 describe each shape’s performance. In applications that require many insertions into the collection, insertion speed might be especially important; for other applications, lookup speed may be more important.

  • Column 6 describes whether each shape allows duplicate elements.

Collection Shape Features

Shape | Ordered? | Indexed? | Insert an element | Search for specified element | Duplicate elements?
List | Yes | No | Fast | Slow | Yes
Array | Yes | By int | Slow | Slow | Yes
Map | No | By key | Fast | Fast | No (keys) Yes (values)

The following table, Characteristics of MFC Collection Classes, summarizes other important characteristics of specific MFC collection classes as a guide to selection. Your choice may depend on whether the class is based on C++ templates, whether its elements can be serialized via MFC’s document serialization mechanism, whether its elements can be dumped via MFC’s diagnostic dumping mechanism, or whether the class is type-safe — that is, whether you can guarantee the type of elements stored in and retrieved from a collection based on the class.

Characteristics of MFC Collection Classes

Class | Uses C++ templates | Can be serialized | Can be dumped | Is type-safe
CArray | Yes | Yes 1 | Yes 1 | No
CByteArray | No | Yes | Yes | Yes 3
CDWordArray | No | Yes | Yes | Yes 3
CList | Yes | Yes 1 | Yes 1 | No
CMap | Yes | Yes 1 | Yes 1 | No
CMapPtrToPtr | No | No | Yes | No
CMapPtrToWord | No | No | Yes | No
CMapStringToOb | No | Yes | Yes | No
CMapStringToPtr | No | No | Yes | No
CMapStringToString | No | Yes | Yes | Yes 3
CMapWordToOb | No | Yes | Yes | No
CMapWordToPtr | No | No | Yes | No
CObArray | No | Yes | Yes | No
CObList | No | Yes | Yes | No
CPtrArray | No | No | Yes | No
CPtrList | No | No | Yes | No
CStringArray | No | Yes | Yes | Yes 3
CStringList | No | Yes | Yes | Yes 3
CTypedPtrArray | Yes | Depends 2 | Yes | Yes
CTypedPtrList | Yes | Depends 2 | Yes | Yes
CTypedPtrMap | Yes | Depends 2 | Yes | Yes
CUIntArray | No | No | Yes | Yes 3
CWordArray | No | Yes | Yes | Yes 3

1. To serialize, you must explicitly call the collection object’s Serialize function; to dump, you must explicitly call its Dump function. You cannot use the form ar << collObj to serialize or the form dmp << collObj to dump.

2. Serializability depends on the underlying collection type. For example, if a typed pointer array is based on CObArray, it is serializable; if based on CPtrArray, it is not serializable. In general, the “Ptr” classes cannot be serialized.

3. If marked Yes in this column, a nontemplate collection class is type-safe provided you use it as intended. For example, if you store bytes in a CByteArray, the array is type-safe. But if you use it to store characters, its type safety is less certain.

See Also Collections: Template-Based Classes, Collections: How to Make a Type-Safe Collection, Collections: Accessing All Members of a Collection


Collections: Template-Based Classes

Home | Overview | How Do I | Sample | Tutorial

This article explains the type-safe template-based collection classes in MFC version 3.0 and later. Using these templates to create type-safe collections is more convenient and provides better type safety than using the collection classes not based on templates.

MFC predefines two categories of template-based collections:

  • Simple array, list, and map classes

    CArray, CList, CMap

  • Arrays, lists, and maps of typed pointers

    CTypedPtrArray, CTypedPtrList, CTypedPtrMap

The simple collection classes are all derived from class CObject, so they inherit the serialization, dynamic creation, and other properties of CObject. The typed pointer collection classes require you to specify the class you derive from — which must be one of the nontemplate pointer collections predefined by MFC, such as CPtrList or CPtrArray. Your new collection class inherits from the specified base class, and the new class’s member functions use encapsulated calls to the base class members to enforce type safety.

For more information about C++ templates, see Template Topics.

Using Simple Array, List, and Map Templates

To use the simple collection templates, you need to know what kind of data you can store in these collections and what parameters to use in your collection declarations.

Simple Array and List Usage

The simple array and list classes, CArray and CList, take two parameters: TYPE and ARG_TYPE. These classes can store any data type, which you specify in the TYPE parameter:

  • Fundamental C++ data types, such as int, char, and float

  • C++ structures and classes

  • Other types that you define

For convenience and efficiency, you can use the ARG_TYPE parameter to specify the type of function arguments. Typically, you specify ARG_TYPE as a reference to the type you named in the TYPE parameter. For example:

CArray<int, int> myArray;
CList<CPerson, CPerson&> myList;

The first example declares an array collection, myArray, that contains ints. The second example declares a list collection, myList, that stores CPerson objects. Certain member functions of the collection classes take arguments whose type is specified by the ARG_TYPE template parameter. For example, the Add member function of class CArray takes an ARG_TYPE argument:

CArray<CPerson, CPerson&> myArray;
CPerson person;
myArray->Add( person );

Simple Map Usage

The simple map class, CMap, takes four parameters: KEY, ARG_KEY, VALUE, and ARG_VALUE. Like the array and list classes, the map classes can store any data type. Unlike arrays and lists, which index and order the data they store, maps associate keys and values: You access a value stored in a map by specifying the value’s associated key. The KEY parameter specifies the data type of the keys used to access data stored in the map. If the type of KEY is a structure or class, the ARG_KEY parameter is typically a reference to the type specified in KEY. The VALUE parameter specifies the type of the items stored in the map. If the type of ARG_VALUE is a structure or class, the ARG_VALUE parameter is typically a reference to the type specified in VALUE. For example:

CMap< int, int, MY_STRUCT, MY_STRUCT& > myMap1;
CMap< CString, LPCSTR, CPerson, CPerson& > myMap2;

The first example stores MY_STRUCT values, accesses them by int keys, and returns accessed MY_STRUCT items by reference. The second example stores CPerson values, accesses them by CString keys, and returns references to accessed items. This example might represent a simple address book, in which you look up persons by last name.

Because the KEY parameter is of type CString and the KEY_TYPE parameter is of type LPCSTR, the keys are stored in the map as items of type CString but are referenced in functions such as SetAt through pointers of type LPCSTR. For example:

CMap< CString, LPCSTR, CPerson, CPerson& > myMap2;
CPerson person;
LPCSTR lpstrName = "Jones";
myMap2->SetAt( lpstrName, person );

Using Typed-Pointer Collection Templates

To use the typed-pointer collection templates, you need to know what kinds of data you can store in these collections and what parameters to use in your collection declarations.

Typed-Pointer Array and List Usage

The typed-pointer array and list classes, CTypedPtrArray and CTypedPtrList, take two parameters: BASE_CLASS and TYPE. These classes can store any data type, which you specify in the TYPE parameter. They are derived from one of the nontemplate collection classes that stores pointers; you specify this base class in BASE_CLASS. For arrays, use either CObArray or CPtrArray. For lists, use either CObList or CPtrList.

In effect, when you declare a collection based on, say CObList, the new class not only inherits the members of its base class, but it also declares a number of additional type-safe member functions and operators that provide type safety by encapsulating calls to the base class members. These encapsulations manage all necessary type conversion. For example:

CTypedPtrArray<CObArray, CPerson*> myArray;
CTypedPtrList<CPtrList, MY_STRUCT*> myList;

The first example declares a typed-pointer array, myArray, derived from CObArray. The array stores and returns pointers to CPerson objects (where CPerson is a class derived from CObject). You can call any CObArray member function, or you can call the new type-safe GetAt and ElementAt functions or use the type-safe [ ] operator.

The second example declares a typed-pointer list, myList, derived from CPtrList. The list stores and returns pointers to MY_STRUCT objects. A class based on CPtrList is used for storing pointers to objects not derived from CObject. CTypedPtrList has a number of type-safe member functions: GetHead, GetTail, RemoveHead, RemoveTail, GetNext, GetPrev, and GetAt.

Typed-Pointer Map Usage

The typed-pointer map class, CTypedPtrMap, takes three parameters: BASE_CLASS, KEY, and VALUE. The BASE_CLASS parameter specifies the class from which to derive the new class: CMapPtrToWord, CMapPtrToPtr, CMapStringToPtr, CMapWordToPtr, CMapStringToOb, and so on. KEY is analogous to KEY in CMap: It specifies the type of the key used for lookups. VALUE is analogous to VALUE in CMap: It specifies the type of object stored in the map. For example:

CTypedPtrMap<CMapPtrToPtr, CString, MY_STRUCT*> myPtrMap;
CTypedPtrMap<CMapStringToOb, CString, CMyObject*> myObjectMap;

The first example is a map based on CMapPtrToPtr — it uses CString keys mapped to pointers to MY_STRUCT. You can look up a stored pointer by calling a type-safe Lookup member function. You can use the [ ] operator to look up a stored pointer and add it if not found. And you can iterate the map using the type-safe GetNextAssoc function. You can also call other member functions of class CMapPtrToPtr.

The second example is a map based on CMapStringToOb — it uses string keys mapped to stored pointers to CMyObject objects. You can use the same type-safe members described in the previous paragraph, or you can call members of class CMapStringToOb.

Note If you specify a class or struct type for the VALUE parameter, rather than a pointer or reference to the type, the class or structure must have a copy constructor.

For related information, see Collections: How to Make a Type-Safe Collection.


Collections: How to Make a Type-Safe Collection

Home | Overview | How Do I | Sample | Tutorial

This article explains how to make type-safe collections for your own data types. Topics include:

  • Using template-based classes for type safety

  • Implementing helper functions

  • Using nontemplate collection classes

The Microsoft Foundation Class Library provides predefined type-safe collections based on C++ templates. Because they are templates, these classes provide type safety and ease of use without the type-casting and other extra work involved in using a nontemplate class for this purpose. The MFC Advanced Concepts sample COLLECT demonstrates the use of template-based collection classes in an MFC application. In general, use these classes any time you write new collections code.

Using Template-Based Classes for Type Safety

To use template-based classes

  1. Declare a variable of the collection class type. For example:
    CList<int, int> m_intList;
  2. Call the member functions of the collection object. For example:
    m_intList.AddTail( 100 );
m_intList.RemoveAll( );
  3. If necessary, implement the helper functions SerializeElements, ConstructElements, and DestructElements. For information on implementing these functions, see Implementing Helper Functions.

This example shows the declaration of a list of integers. The first parameter in step 1 is the type of data stored as elements of the list. The second parameter specifies how the data is to be passed to and returned from member functions of the collection class, such as Add and GetAt.

Implementing Helper Functions

The template-based collection classes CArray, CList, and CMap use seven global helper functions that you can customize as needed for your derived collection class. For information on these helper functions, see Collection Class Helpers in the Class Library Reference. Three of these helper functions are used in constructing, destructing, and serializing collection elements; implementations of these functions are necessary for most uses of the template-based collection classes.

Construction and Destruction

The helper functions ConstructElements and DestructElements are called by members that respectively add and remove elements from a collection.

Helper Called directly by Called indirectly by
ConstructElements CArray::SetSize
CArray::InsertAt 		CList::AddHead
CList::AddTail
CList::InsertBefore
CList::InsertAfter
CMap::operator [ ]
DestructElements CArray::SetSize
CArray::RemoveAt
CList::RemoveAll
CMap::RemoveAll 		CList::RemoveHead
CList::RemoveTail
CList::RemoveAt
CMap::RemoveKey

You should override these functions if their default action is not suitable for your collection class. The default implementation of ConstructElements sets to 0 the memory that is allocated for new elements of the collection and calls the constructor of each element. The default implementation of DestructElements calls the destructor for each element.

In general, overriding ConstructElements is necessary whenever the collection stores objects that require a call to a constructor (or other initializing function), or when the objects have members requiring such calls. Overriding DestructElements is necessary when an object requires special action, such as freeing memory allocated from the heap, when the object is destroyed.

For example, you might override ConstructElements for an array of CPerson objects as follows:

class CPerson : public CObject { . . . };
CArray< CPerson, CPerson& > personArray;

template <> void AFXAPI ConstructElements <CPerson> ( CPerson* pNewPersons, int nCount )
{
    for ( int i = 0; i < nCount; i++, pNewPersons++ )
    {
        // call CPerson default constructor directly
        new( pNewPersons )CPerson;
    }
}

This override iterates through the new CPerson objects, calling each object’s constructor. The special new operator used here constructs a new CPerson object in place rather than allocating memory from the heap.

Serializing Elements

The CArray, CList, and CMap classes call SerializeElements to store collection elements to or read them from an archive.

The default implementation of the SerializeElements helper function does a bitwise write from the objects to the archive, or a bitwise read from the archive to the objects, depending on whether the objects are being stored in or retrieved from the archive. Override SerializeElements if this action is not appropriate.

If your collection stores objects derived from CObject and you use the IMPLEMENT_SERIAL macro in the implementation of the collection element class, you can take advantage of the serialization functionality built into CArchive and CObject:

class CPerson : public CObject { . . . };
CArray< CPerson, CPerson& > personArray;

template <> void AFXAPI SerializeElements <CPerson> ( CArchive& ar, CPerson* pNewPersons, int nCount )
{
    for ( int i = 0; i < nCount; i++, pNewPersons++ )
    {
        // Serialize each CPerson object
        pNewPersons->Serialize( ar );
    }
}

The overloaded insertion operators for CArchive call CObject::Serialize (or an override of that function) for each CPerson object.

Using Nontemplate Collection Classes

MFC also supports the collection classes introduced with MFC version 1.0. These classes are not based on templates. They can be used to contain data of the supported types CObject*, UINT, DWORD, and CString. You can use these predefined collections (such as CObList) to hold collections of any objects derived from CObject. MFC also provides other predefined collections to hold primitive types such as UINT and void pointers (void*). In general, however, it is often useful to define your own type-safe collections to hold objects of a more specific class and its derivatives. Note that doing so with the collection classes not based on templates is more work than using the template-based classes.

There are two ways to create type-safe collections with the nontemplate collections:

  1. Use the nontemplate collections, with type casting if necessary. This is the easier approach.

  2. Derive from and extend a nontemplate type-safe collection.

To use the nontemplate collections with type casting

  • Use one of the nontemplate classes, such as CWordArray, directly.

    For example, you can create a CWordArray and add any 32-bit values to it, then retrieve them. There is nothing more to do. You just use the predefined functionality.

    You can also use a predefined collection, such as CObList, to hold any objects derived from CObject. A CObList collection is defined to hold pointers to CObject. When you retrieve an object from the list, you may have to cast the result to the proper type since the CObList functions return pointers to CObject. For example, if you store CPerson objects in a CObList collection, you have to cast a retrieved element to be a pointer to a CPerson object. The following example uses a CObList collection to hold CPerson objects:

    class CPerson : public CObject {...};

CPerson* p1 = new CPerson(...);
CObList myList;

myList.AddHead( p1 );   // No cast needed
CPerson* p2 = ( CPerson* )myList.GetHead();

    This technique of using a predefined collection type and casting as necessary may be adequate for many of your collection needs. If you need further functionality or more type safety, use a template-based class, or follow the next procedure.

To derive and extend a nontemplate type-safe collection

  • Derive your own collection class from one of the predefined nontemplate classes.

    When you derive your class, you can add type-safe wrapper functions to provide a type-safe interface to existing functions.

    For example, if you derived a list from CObList to hold CPerson objects, you might add the wrapper functions AddHeadPerson and GetHeadPerson, as shown below.

    class CPersonList : public CObList
{
public:
    void AddHeadPerson( CPerson* person )
        {AddHead( person );}

    const CPerson* GetHeadPerson()
        {return (CPerson*)GetHead();}
};

    These wrapper functions provide a type-safe way to add and retrieve CPerson objects from the derived list. You can see that for the GetHeadPerson function, you are simply encapsulating the type casting.

    You can also add new functionality by defining new functions that extend the capabilities of the collection rather than just wrapping existing functionality in type-safe wrappers. For example, the article Collections: Deleting All Objects in a CObject Collection describes a function to delete all the objects contained in a list. This function could be added to the derived class as a member function.

For related information, see Technical Note 4: C++ Template Tool.


Collections: Accessing All Members of a Collection

Home | Overview | How Do I | Sample | Tutorial

The MFC array collection classes — both template-based and not — use indexes to access their elements. The MFC list and map collection classes — both template-based and not — use an indicator of type POSITION to describe a given position within the collection. To access one or more members of these collections, you first initialize the position indicator and then repeatedly pass that position to the collection and ask it to return the next element. The collection is not responsible for maintaining state information about the progress of the iteration. That information is kept in the position indicator. But, given a particular position, the collection is responsible for returning the next element.

The following procedures show how to iterate over the three main types of collections provided with MFC:

  • Iterating an array

  • Iterating a list

  • Iterating a map

To iterate an array

  • Use sequential index numbers with the GetAt member function:
    CTypedPtrArray<CObArray, CPerson*> myArray;

for( int i = 0; i < myArray.GetSize();i++ )
{
    CPerson* thePerson = myArray.GetAt( i );
    ...
}

    This example uses a typed pointer array that contains pointers to CPerson objects. The array is derived from class CObArray, one of the nontemplate predefined classes. GetAt returns a pointer to a CPerson object. For typed pointer collection classes — arrays or lists — the first parameter specifies the base class; the second parameter specifies the type to store.

    The CTypedPtrArray class also overloads the [ ] operator so that you can use the customary array-subscript syntax to access elements of an array. An alternative to the statement in the body of the for loop above is

    CPerson* thePerson = myArray[ i ];

    This operator exists in both const and non-const versions. The const version, which is invoked for const arrays, can appear only on the right side of an assignment statement.

To iterate a list

  • Use the member functions GetHeadPosition and GetNext to work your way through the list:
    CTypedPtrList<CObList, CPerson*> myList;

POSITION pos = myList.GetHeadPosition();
while( pos != NULL )
{
    CPerson* thePerson = myList.GetNext( pos );
    ...
}

    This example uses a typed pointer list to contain pointers to CPerson objects. The list declaration resembles the one for the array in the procedure To iterate an array but is derived from class CObList. GetNext returns a pointer to a CPerson object.

To iterate a map

  • Use GetStartPosition to get to the beginning of the map and GetNextAssoc to repeatedly get the next key and value from the map, as shown by the following example:
    CMap<CString, LPCTSTR, CPerson*, CPerson*> myMap;

POSITION pos = myMap.GetStartPosition();
while( pos != NULL )
{
    CPerson* pPerson;
    CString string;
    // Get key ( string ) and value ( pPerson )
    myMap.GetNextAssoc( pos, string, pPerson );
    // Use string and pPerson
}

    This example uses a simple map template (rather than a typed pointer collection) that uses CString keys and stores pointers to CPerson objects. When you use access functions such as GetNextAssoc, the class provides pointers to CPerson objects. If you use one of the nontemplate map collections instead, you must cast the returned CObject pointer to a pointer to a CPerson.

    Note For nontemplate maps, the compiler requires a reference to a CObject pointer in the last parameter to GetNextAssoc. On input, you must cast your pointers to that type, as shown in the next example.

    The template solution is simpler and provides better type safety. The nontemplate code is more complicated, as you can see here:

    CMapStringToOb myMap;    // A nontemplate collection class

POSITION pos = myMap.GetStartPosition( );
while( pos != NULL )
{
    CPerson* pPerson;
    CString string;
    // Gets key (string) and value (pPerson)
    myMap.GetNextAssoc( pos, string,
                            (CObject*&)pPerson );
    ASSERT( pPerson->IsKindOf(
                 RUNTIME_CLASS( CPerson ) ) );
    // Use string and pPerson
}

For related information, see Collections: Deleting All Objects in a CObject Collection.


Collections: Deleting All Objects in a CObject Collection

Home | Overview | How Do I | Sample | Tutorial

This article explains how to delete all objects in a collection (without deleting the collection object itself).

To delete all the objects in a collection of CObjects (or of objects derived from CObject), you use one of the iteration techniques described in the article Collections: Accessing All Members of a Collection to delete each object in turn.

Caution Objects in collections can be shared. That is, the collection keeps a pointer to the object, but other parts of the program may also have pointers to the same object. You must be careful not to delete an object that is shared until all the parts have finished using the object.

This article shows you how to delete the objects in:

  • A list

  • An array

  • A map

To delete all objects in a list of pointers to CObject

  1. Use GetHeadPosition and GetNext to iterate through the list.

  2. Use the delete operator to delete each object as it is encountered in the iteration.

  3. Call the RemoveAll function to remove all elements from the list after the objects associated with those elements have been deleted.

The following example shows how to delete all objects from a list of CPerson objects. Each object in the list is a pointer to a CPerson object that was originally allocated on the heap.

CTypedPtrList<CObList, CPerson*> myList;
POSITION pos = myList.GetHeadPosition();

while( pos != NULL )
{
    delete myList.GetNext( pos );
}
myList.RemoveAll();

The last function call, RemoveAll, is a list member function that removes all elements from the list. The member function RemoveAt removes a single element.

Notice the difference between deleting an element’s object and removing the element itself. Removing an element from the list merely removes the list’s reference to the object. The object still exists in memory. When you delete an object, it ceases to exist and its memory is reclaimed. Thus, it is important to remove an element immediately after the element’s object has been deleted so that the list won’t try to access objects that no longer exist.

To delete all elements in an array

  1. Use GetSize and integer index values to iterate through the array.

  2. Use the delete operator to delete each element as it is encountered in the iteration.

  3. Call the RemoveAll function to remove all elements from the array after they have been deleted.

    The code for deleting all elements of an array is as follows:

    CArray<CPerson*, CPerson*> myArray;

int i = 0;
while (i < myArray.GetSize() )
{
    delete myArray.GetAt( i++ );
}

myArray.RemoveAll();

As with the list example above, you can call RemoveAll to remove all elements in an array or RemoveAt to remove an individual element.

To delete all elements in a map

  1. Use GetStartPosition and GetNextAssoc to iterate through the array.

  2. Use the delete operator to delete the key and/or value for each map element as it is encountered in the iteration.

  3. Call the RemoveAll function to remove all elements from the map after they have been deleted.

    The code for deleting all elements of a CMap collection is as follows. Each element in the map has a string as the key and a CPerson object (derived from CObject) as the value.

    CMap<CString, LPCSTR, CPerson*, CPerson*> myMap;
// ... Add some key-value elements ...
// Now delete the elements
POSITION pos = myMap.GetStartPosition();
while( pos != NULL )
{
    CPerson* pPerson;
    CString string;
    // Gets key (string) and value (pPerson)
    myMap.GetNextAssoc( pos, string, pPerson );
    delete pPerson;
}
// RemoveAll deletes the keys
myMap.RemoveAll();

You can call RemoveAll to remove all elements in a map or RemoveKey to remove an individual element with the specified key.


Collections: Creating Stack and Queue Collections

Home | Overview | How Do I | Sample | Tutorial

This article explains how to create other data structures, such as stacks and queues, from MFC list classes. The examples use classes derived from CList, but you can use CList directly unless you need to add functionality.

Stacks

Because the standard list collection has both a head and a tail, it is easy to create a derived list collection that mimics the behavior of a last-in-first-out stack. A stack is like a stack of trays in a cafeteria. As trays are added to the stack, they go on top of the stack. The last tray added is the first to be removed. The list collection member functions AddHead and RemoveHead can be used to add and remove elements specifically from the head of the list; thus, the most recently added element is the first to be removed.

To create a stack collection

  • Derive a new list class from one of the existing MFC list classes and add more member functions to support the functionality of stack operations.

    The following example shows how to add member functions to push elements on to the stack, peek at the top element of the stack, and pop the top element from the stack:

    class CTray : public CObject { ... };

class CStack : public CTypedPtrList< CObList, CTray* >
{
public:
    // Add element to top of stack
    void Push( CTray* newTray )
        { AddHead( newTray ); }

    // Peek at top element of stack
    CTray* Peek()
        { return IsEmpty() ? NULL : GetHead(); }

    // Pop top element off stack
    CTray* Pop()
        { return RemoveHead(); }
};

Note that this approach exposes the underlying CObList class. The user can call any CObList member function, whether it makes sense for a stack or not.

Queues

Because the standard list collection has both a head and a tail, it is also easy to create a derived list collection that mimics the behavior of a first-in-first-out queue. A queue is like a line of people in a cafeteria. The first person in line is the first to be served. As more people come, they go to the end of the line to wait their turn. The list collection member functions AddTail and RemoveHead can be used to add and remove elements specifically from the head or tail of the list; thus, the most recently added element is always the last to be removed.

To create a queue collection

  • Derive a new list class from one of the predefined list classes provided with the Microsoft Foundation Class Library and add more member functions to support the semantics of queue operations.

    The following example shows how you can append member functions to add an element to the end of the queue and get the element from the front of the queue.

    class CPerson : public CObject { ... };

class CQueue : public CTypedPtrList< CObList, CPerson* >
{
public:
    // Go to the end of the line
    void AddToEnd( CPerson* newPerson )
        { AddTail( newPerson ); }        // End of the queue

    // Get first element in line
    CPerson* GetFromFront()
        { return IsEmpty() ? NULL : RemoveHead(); }
};


Connection Points

Home

This article explains how to implement connection points (formerly known as OLE connection points) using CCmdTarget and CConnectionPoint.

In the past, the Component Object Model (COM) defined a general mechanism (IUnknown::QueryInterface) that allowed objects to implement and expose functionality in interfaces. However, a corresponding mechanism that allowed objects to expose their capability to call specific interfaces was not defined. That is, COM defined how incoming pointers to objects (pointers to that object’s interfaces) were handled, but it did not have an explicit model for outgoing interfaces (pointers the object holds to other objects’ interfaces). COM now has a model, called connection points, that supports this functionality.

A connection has two parts: the object calling the interface, called the source, and the object implementing the interface, called the sink. A connection point is the interface exposed by the source. By exposing a connection point, a source allows sinks to establish connections to itself (the source). Through the connection point mechanism (the IConnectionPoint interface), a pointer to the sink interface is passed to the source object. This pointer provides the source with access to the sink’s implementation of a set of member functions. For example, to fire an event implemented by the sink, the source can call the appropriate method of the sink’s implementation. The following figure demonstrates the connection point just described.

An Implemented Connection Point

MFC implements this model in the CConnectionPoint and CCmdTarget classes. Classes derived from CConnectionPoint implement the IConnectionPoint interface, used to expose connection points to other objects. Classes derived from CCmdTarget implement the IConnectionPointContainer interface, which can enumerate all of an object’s available connection points or find a specific connection point.

For each connection point implemented in your class, you must declare a connection part that implements the connection point. If you implement one or more connection points, you must also declare a single connection map in your class. A connection map is a table of connection points supported by the ActiveX control.

The following examples demonstrate a simple connection map and one connection point. The first example declares the connection map and point; the second example implements the map and point. Note that CMyClass must be a CCmdTarget-derived class. In the first example, code is inserted in the class declaration, under the protected section:

class CMyClass : public CCmdTarget
{
 ...
 protected:
// Connection point for ISample interface
    BEGIN_CONNECTION_PART(CMyClass, SampleConnPt)
        CONNECTION_IID(IID_ISampleSink)
    END_CONNECTION_PART(SampleConnPt)

    DECLARE_CONNECTION_MAP()

};

The BEGIN_CONNECTION_PART and END_CONNECTION_PART macros declare an embedded class, XSampleConnPt (derived from CConnectionPoint) that implements this particular connection point. If you want to override any CConnectionPoint member functions or add member functions of your own, declare them between these two macros. For example, the CONNECTION_IID macro overrides the CConnectionPoint::GetIID member function when placed between these two macros.

In the second example, code is inserted in the control’s implementation file (.CPP). This code implements the connection map, which includes the connection point, SampleConnPt:

BEGIN_CONNECTION_MAP(CMyClass, CMyBaseClass)
    CONNECTION_PART(CMyClass, IID_ISampleSink, SampleConnPt)
END_CONNECTION_MAP()

If your class has more than one connection point, insert additional CONNECTION_PART macros between the BEGIN_CONNECTION_MAP and END_CONNECTION_MAP macros.

Finally, add a call to EnableConnections in the class’s constructor. For example:

CMyClass::CMyClass()
{
EnableConnections();
...
}

Once this code has been inserted, your CCmdTarget-derived class exposes a connection point for the ISampleSink interface. The following figure illustrates this example.

A Connection Point Implemented with MFC

Usually, connection points support “multicasting” — the ability to broadcast to multiple sinks connected to the same interface. The following example fragment demonstrates how to multicast by iterating through each sink on a connection point:

void CMyClass::CallSinkFunc()
{
    const CPtrArray* pConnections = m_xSampleConnPt.GetConnections();
    ASSERT(pConnections != NULL);

    int cConnections = pConnections->GetSize();
    ISampleSink* pSampleSink;
    for (int i = 0; i < cConnections; i++)
    {
        pSampleSink = (ISampleSink*)(pConnections->GetAt(i));
        ASSERT(pSampleSink != NULL);
        pSampleSink->SinkFunc();
    }
}

This example retrieves the current set of connections on the SampleConnPt connection point with a call to CConnectionPoint::GetConnections. It then iterates through the connections and calls ISampleSink::SinkFunc on every active connection.


Database Topics (General)

Home | Overview | How Do I | FAQ | ODBC Driver List

MFC supports two different kinds of database access:

  • Via Data Access Objects (DAO) and the Microsoft Jet database engine

  • Via Open Database Connectivity (ODBC) and an ODBC driver

Both of these supply abstractions that simplify working with databases, complete with the speed, power, and flexibility of C++. Both integrate your data access work with the MFC application framework.

Frequently Asked Questions About MFC Database Support

  • What data sources can I access with DAO and ODBC?

  • Can I call DAO or ODBC APIs directly while using the classes?

  • What ODBC drivers are provided?

  • What ODBC drivers are installed by default?

What do you want to do?

  • Learn what DAO and ODBC are.

  • Learn when to use the MFC database classes.

  • Learn about the MFC database programming model.

  • Choose between the MFC DAO classes and the MFC ODBC classes.

  • Learn how to install database support if not already installed.

  • Find out which data sources I can access with DAO or ODBC.

  • Learn how the documentation for database support is organized.

  • Learn how the database classes work with MFC’s document/view architecture

  • Learn what a database record is

  • Learn what a database schema is

  • Learn what database catalog information is


What Are DAO and ODBC?

Home | Overview | How Do I | FAQ | ODBC Driver List

Both Data Access Objects (DAO) and Open Database Connectivity (ODBC) are application programming interfaces (APIs) that give you the ability to write applications that are independent of any particular database management system (DBMS).

DAO is familiar to database programmers using Microsoft Access Basic or Microsoft Visual Basic. DAO uses the Microsoft Jet database engine to provide a set of data access objects: database objects, tabledef and querydef objects, recordset objects, and others. DAO works best with .MDB files like those created by Microsoft Access, but you can also access ODBC data sources through DAO and the Microsoft Jet database engine.

ODBC provides an API that different database vendors implement via ODBC drivers specific to a particular database management system (DBMS). Your program uses this API to call the ODBC Driver Manager, which passes the calls to the appropriate driver. The driver, in turn, interacts with the DBMS using Structured Query Language (SQL).

Note As a major part of the Microsoft Windows Open Standards Architecture (WOSA), ODBC is here for the long run. DAO is optimized around the Microsoft Jet database engine, but you can still access ODBC and other external data sources via that engine, and the distinct ODBC API and the MFC classes based on it are still available and still have their role to play in your selection of database tools.


When Should I Use the Database Classes?

Home | Overview | How Do I | FAQ | ODBC Driver List

Many applications require data storage in a database, and many other applications could benefit from using a database. A database gives you a flexible data repository that can be accessed, in many cases, by multiple users and multiple applications. Databases can store large amounts of data and provide fast data access for queries and updates.


What Is the MFC Database Programming Model?

Home | Overview | How Do I | FAQ | ODBC Driver List

Although MFC implements DAO and ODBC quite differently underneath, they have similar interfaces that it relatively easy to port your applications from one to the other, particularly from ODBC to DAO. (For information about porting from ODBC to DAO, see Technical Note 55.) The DAO and ODBC interfaces in MFC are also very similar to that in Visual Basic.

The MFC programming model provides a database object for each open database. The database object represents your connection to the database. You make queries and updates via recordset objects. DAO provides additional objects, for working with table structure, saving queries for reuse, and so on, described later. MFC supplies classes for each of these objects: one set of classes for DAO and another set for ODBC.

Using MFC makes database programming easier. The DAO and ODBC database classes supply high-level abstractions that free you from using DAO or ODBC directly. Writing to their APIs is more complex than using the MFC classes. This is especially true if you are writing small, relatively simple applications.

The database classes add the following components to the MFC class library:

  • C++ database classes that supply a high-level API for accessing databases through either DAO or ODBC.

  • Extensions to AppWizard and ClassWizard for creating application-specific database classes.

  • Sample programs that illustrate use of the classes and the wizards.

  • Online documentation that includes overviews, tutorials, articles on programming topics, and class reference materials.

For information about these components, see this group of articles and the articles DAO and MFC and ODBC and MFC.

What do you want to know more about?

  • Choosing between DAO and ODBC

  • Availability of database definition language (DDL) and database manipulation language (DML) in DAO and ODBC

  • Installing MFC database support

  • The DAO and ODBC classes in MFC

  • Database sample programs for DAO and ODBC

  • Database programming documentation

  • How MFC implements DAO

  • How MFC implements ODBC


Should I Use DAO or ODBC?

Home | Overview | How Do I | FAQ | ODBC Driver List

Which set of MFC classes should you use? This depends on your needs:

  • Use the ODBC classes if you are working strictly with ODBC data sources, particularly in client/server situations, where the MFC ODBC classes provide better performance.

  • Use the DAO classes if you are working primarily with Microsoft Jet (.MDB) databases or with other database formats that the Microsoft Jet database engine can read directly. For a list of these, see What Databases Can I Access with DAO and ODBC?

  • Access ODBC data sources via the DAO classes when you want the speed of the Microsoft Jet database engine and the extra functionality of the DAO classes.

Note DAO requires additional hard disk space.

The DAO classes have the following advantages:

  • Better performance in some cases, particularly when using Microsoft Jet (.MDB) databases.

  • Compatibility with the ODBC classes and with Microsoft Access Basic and Microsoft Visual Basic.

  • Access to validation rules.

  • Ability to specify relations between tables.

  • A richer data access model, with support for Data Definition Language (DDL) as well as Data Manipulation Language (DML). For details, see Database Definition and Manipulation.

Here’s a summary of the key differences to help you choose:

Choosing Between MFC’s DAO and ODBC Classes

Can I... | with DAO Classes? | with ODBC Classes?
Access .MDB files | Yes | Yes
Access ODBC data sources | Yes | Yes
Available for 16 Bit | No | Yes
Available for 32 Bit | Yes | Yes
Database compaction | Yes | No
Database engine support | Microsoft Jet database engine | Target DBMS
DDL support | Yes | Only via direct ODBC calls
DML support | Yes | Yes
Nature of the MFC implementation | “Wrapper” of DAO core functions | Simplified abstraction rather than a “wrapper” of the ODBC API
Optimal for | .MDB files (Microsoft Access) | Any DBMS for which you have a driver, especially in client/server situations
Transaction support | Per “workspace” or, for ODBC data, per database | Per database

Keep in mind that the capabilities of ODBC drivers vary. See the ODBC Programmer’s Reference and the help file for your ODBC driver for more information. For information about using ODBC via DAO, see the article DAO External: Working with External Data Sources.


Database Definition and Manipulation

Home | Overview | How Do I | FAQ | ODBC Driver List

The MFC DAO classes support two kinds of access to databases:

  • Data definition language (DDL) You can create and delete databases, create and delete tables, define table fields and indexes, and take other actions that affect the structure of your database.

  • Data manipulation language (DML) You can run queries, add, delete, and edit records, and otherwise manipulate the content of your database.

The MFC ODBC classes support only DML, but you can call ODBC API functions directly to carry out DDL tasks.


Installing MFC Database Support

Home | Overview | How Do I | FAQ | ODBC Driver List

When you run Setup for Visual C++, you can choose whether or not to install database components:

  • If you do install database components, you can select any ODBC drivers you need.

  • If you are working with ODBC data sources, you might need ODBC drivers regardless of whether you plan to use DAO or ODBC.

  • If you select any drivers, they are installed on your hard disk, along with the ODBC driver manager and the ODBC administrator program.

In addition, Setup installs necessary components from the DAO software development kit (SDK). This includes help files, which are not integrated with this documentation.

ODBC Drivers Installed

If you select a Typical Installation, Setup installs the following ODBC drivers:

  • Microsoft FoxPro

  • Microsoft Access

  • dBASE

  • Microsoft SQL Server

If you select a Custom Installation, you can also install the following additional ODBC drivers:

  • Text files

  • Paradox

  • Microsoft Excel

See the article ODBC Driver List for a list of ODBC drivers included in this version of Visual C++ and for information about obtaining additional drivers.

DAO SDK Components Installed

The following components of the DAO SDK are installed by default:

  • Microsoft Jet (3.x MDB)

  • Microsoft Jet (1.x, 2.x)

  • All of the database formats listed under What Databases Can I Access with DAO and ODBC

If you wish to install other DAO SDK components, such as the DAO SDK C++ classes, example files, or the Windows Help version of the DAO Help file, run \DAOSDK\Disk1\Setup.exe on the Visual C++ CD.

ODBC SDK Components Installed

Visual C++ includes many key ODBC components, including the required header files, libraries, DLLs, and tools. These include the ODBC Administrator control panel application, which you use to configure ODBC data sources, and the ODBC Driver Manager. Also included are ODBC drivers for many popular DBMSs, as listed in ODBC Drivers Installed.

The ODBC SDK, which gives you additional information and tools for writing and testing ODBC drivers, is available on the MSDN Library CD. Note that the ODBC SDK is no longer included on the Visual C++ CD.


More Information About the DAO and ODBC Classes

Home | Overview | How Do I | FAQ | ODBC Driver List

Because MFC implements DAO and ODBC differently, the documentation for each class is almost completely separate. The DAO SDK is provided on the Visual C++ CD, and the ODBC SDK is provided on the MSDN Library CD. The table below lists the next article to read if you're just beginning to study the MFC DAO classes or the MFC ODBC classes.

Further Reading About DAO and ODBC in MFC

For more information about... | See...
The MFC DAO classes | DAO and MFC
The MFC ODBC classes | ODBC and MFC

Tip In any topic in the MFC DAO documentation, you’ll find a See Also reference. One topic always available in the See Also list is the topic DAO: Where Is..., which helps you quickly locate the information you seek.

What do you want to know more about?

  • MFC database documentation

  • Using database classes with documents and views

  • Using database classes without documents and views


MFC Database Documentation

Home | Overview | How Do I | FAQ | ODBC Driver List

The MFC documentation for DAO and ODBC classes consists of the components listed in the following table:

MFC Database Documentation

For documentation on... | See...
DAO database tutorial | Data Access Objects (DAO) Tutorial in Tutorials
ODBC database tutorial | Creating a Database Application in Tutorials
Classes for both DAO and ODBC | The class name in the Class Library Reference
Global functions and macros for both DAO and ODBC | The function or macro name in the Class Library Reference
Programming with the MFC DAO classes | The article DAO and MFC
Programming with the MFC ODBC classes | The article ODBC and MFC
Technical notes for both DAO and ODBC | MFC Technical Notes
Sample applications | MFC Samples

MFC Documentation and DAO Documentation

Throughout the MFC documentation for the MFC DAO classes, you'll find references to topics in the DAO SDK documentation, included in the online documentation. Because MFC encapsulates, or "wraps," DAO, the MFC documentation:

  • Focuses on MFC and how it differs from the underlying DAO implementation.

  • Points you to the DAO SDK Help topics for the underlying details. These cross references are always worded as “topic X in DAO Help.”

  • Points out differences where MFC does things differently from the way DAO does them. MFC doesn't wrap all of DAO. For example, MFC doesn't supply objects for DAO's security functionality.

Important The DAO SDK help is a separate help file. There are no hypertext links from this documentation to DAO help in this version of Visual C++.

Note You might have to do some translating when you are browsing topics in DAO SDK Help. Examples in the primary DAO SDK documentation are written in the Basic programming language, not C++. (But the DAO SDK supplies a set of C++ examples that don’t use MFC.) For guidance, see the examples that appear in these articles and the MFC DAO sample applications, listed under Visual C++ Programming Guide/Samples/MFC Samples/Databases (ODBC and DAO) in the documentation.

MFC Documentation and ODBC Documentation

The MFC documentation for the MFC ODBC classes is organized differently. The MFC ODBC classes supply a high-level abstraction that rests on ODBC rather than a "wrapper" of the ODBC API. Therefore, the two documentation sets are less connected than are the MFC and DAO documentation sets. The ODBC documentation uses the C language, which is much closer to C++ than is Basic.

See Also DAO: Where Is..., Data Access Objects (DAO), ODBC


MFC: Using Database Classes with Documents and Views

Home | Overview | How Do I | FAQ | ODBC Driver List

You can use the MFC database classes ? DAO or ODBC ? with or without the document/view architecture. This article emphasizes working with documents and views. It explains:

  • How to write a form-based application using a CRecordView or CDaoRecordView object as the main view on your document.

  • How to use recordset objects in your documents and views.

  • Other considerations.

For alternatives, see the article MFC: Using Database Classes Without Documents and Views.

Writing a Form-Based Application

Many data-access applications are based on forms. The user interface is a form containing controls in which the user examines, enters, or edits data. To make your application form-based, use class CRecordView or CDaoRecordView. You can specify CRecordView or CDaoRecordView for your view class when you run AppWizard, or you can use ClassWizard later to create a CRecordView-derived or CDaoRecordview-derived class.

In a form-based application, each record view object stores a pointer to a CRecordset or CDaoRecordset object. The framework’s record field exchange (RFX) mechanism exchanges data between the recordset and the data source. The dialog data exchange (DDX) mechanism exchanges data between the field data members of the recordset object and the controls on the form. CRecordView or CDaoRecordView also provides default command handler functions for navigating from record to record on the form.

To create a form-based application with AppWizard

  • See the article Overview: Creating a Program That Supports a Database.

To add a database form to your application with ClassWizard

  • See the article ClassWizard: Creating a Database Form.

For a full discussion of forms, see the article Record Views. For an example of an application with multiple record views on a database, see the MFC tutorial sample ENROLL, Step 4. Step 4 is not covered in the Data Access Objects (DAO) Tutorial, but you can examine the code in the sample.

Using Recordsets in Documents and Views

Many simple form-based applications don’t need “documents.” If your application is more complex, you’ll probably want to use a document as a proxy for the database, storing a CDatabase or CDaoDatabase object that connects to the data source. Form-based applications usually store a pointer to a recordset object in the view. Other kinds of database applications store recordsets and CDatabase or CDaoDatabase objects in the document. Here are some possibilities for using documents in database applications:

  • If you’re accessing a recordset in a local context, create CRecordset or CDaoRecordset objects locally in member functions of the document or the view, as needed.

    Declare a recordset object as a local variable in a function. Pass NULL to the constructor, which causes the framework to create and open a temporary CDatabase or CDaoDatabase object for you. As an alternative, pass a pointer to a CDatabase or CDaoDatabase object. Use the recordset within the function and let it be destroyed automatically when the function exits.

    When you pass NULL to a recordset constructor, the framework uses information returned by the recordset’s GetDefaultConnect member function to create a CDatabase or CDaoDatabase object and open it. The wizards implement GetDefaultConnect for you.

  • If you’re accessing a recordset during the lifetime of your document, embed one or more CRecordset or CDaoRecordset objects in your document.

    Construct the recordset objects either when you initialize the document or as needed. You might write a function that returns a pointer to the recordset if it already exists, or constructs and opens the recordset if it doesn’t exist yet. Close, delete, and re-create the recordset as needed, or call its Requery member function to refresh the records.

  • If you’re accessing a data source during the lifetime of your document, embed a CDatabase or CDaoDatabase object or store a pointer to a CDatabase or CDaoDatabase object in it.

    The CDatabase or CDaoDatabase object manages a connection to your data source. The object is constructed automatically during document construction, and you call its Open member function when you initialize the document. When you construct recordset objects in document member functions, you pass a pointer to the document’s CDatabase or CDaoDatabase object. This associates each recordset with its data source. The database object is usually destroyed when the document closes. The recordset objects are typically destroyed when they exit the scope of a function.

Other Factors

Form-based applications often do not have any use for the framework’s document serialization mechanism, so you might want to remove, disable, or replace the New and Open commands on the File menu. See the article Serialization: Serialization vs. Database Input/Output.

You might also want to make use of the many user-interface possibilities that the framework can support. For example, you could use multiple CRecordView or CDaoRecordView objects in a splitter window, open multiple recordsets in different multiple document interface (MDI) child windows, and so on.

You might want to implement printing of whatever is in your view — whether it’s a form implemented with CRecordView or CDaoRecordView or something else. As classes derived from CFormView, CRecordView and CDaoRecordView don’t support printing, but you can override the OnPrint member function to allow printing. For more information, see class CFormView.

You might not want to use documents and views at all. In that case, see the article MFC: Using Database Classes Without Documents and Views.


MFC: Using Database Classes Without Documents and Views

Home | Overview | How Do I | FAQ | ODBC Driver List

Sometimes you might not want to use the framework’s document/view architecture in your database applications. This article explains:

  • When you don’t need to use document/view functionality such as document serialization.

  • AppWizard options to support applications without serialization and without document-related File menu commands such as New, Open, Save, and Save As.

  • How to work with an application that uses a minimal document.

  • How to structure an application with no document or view.

When You Don’t Need Documents

Some applications have a distinct concept of a “document.” These applications typically load all or most of a file from storage into memory with a File Open command. They write the updated file back to storage all at once with a File Save or Save As command. What the user sees is a data file.

Some categories of applications, however, don’t require a document. Database applications operate in terms of “transactions.” The application selects records from a database and presents them to the user, often one at a time. What the user sees is usually a single current record, which may be the only one in memory.

If your application doesn’t require a document for storing data, you can dispense with some or all of the framework’s document/view architecture. How much you dispense with depends on the approach you prefer. You might:

  • Use a minimal document as a place to store a connection to your data source but dispense with normal document features such as serialization. This is useful when you want several views of the data and would like to synchronize all of the views, updating them all at once and so on.

  • Use a frame window, into which you draw directly, rather than using a view. In this case you would omit the document and store any data or data connections in the frame-window object.

AppWizard Options for Documents and Views

If you use AppWizard to create your application, all of the database options produce applications with documents and views. Some of the options provide documents and views that omit unneeded document functionality. Here are the kinds of document/view support for each option.

AppWizard Options for Documents and Views

Option | View | Document
None (no database support). | Derived from CView. | Full document support including serialization and New, Open, Save, and Save As commands on the File menu.
Only include header files. | Derived from CView. | Same as None option. You can store CDatabase or CDaoDatabase and/or CRecordset or CDaoRecordset objects in your document or your view.
A database view, without file support. | Derived from CRecordView or CDaoRecordView. | Document does not support serialization or the New, Open, Save, and Save As commands. You can use it to store your CRecordset or CDaoRecordset and to coordinate multiple views.
Both a database view and file support. | Derived from CRecordView or CDaoRecordView. | Full document support, including serialization and document-related File menu commands. Use serialization for special purposes, such as storing user profile information.

For a discussion of using the AppWizard options “A database view, without file support” and “Both a database view and file support,” see Applications with Minimal Documents.

For a discussion of writing applications with no document, see Applications with No Document.

For a discussion of alternatives to serialization, and alternative uses for serialization, see the article Serialization: Serialization vs. Database Input/Output.

Applications with Minimal Documents

AppWizard has two options that support form-based data-access applications. Each option creates a CRecordView-or CDaoRecordView derived view class and a document. They differ in what they leave out of the document.

A Document Without File Support

Select the AppWizard database option “A database view without file support” if you don’t need document serialization. The document serves the following useful purposes:

  • It’s a convenient place to store a CRecordset or CDaoRecordset.

    This usage parallels ordinary document concepts: the document “stores” the data — or, in this case, a set of records — and the view is a view of the document.

  • If your application presents multiple views (such as multiple record views), a document supports coordinating the views.

    If multiple views show the same data, you can use the CDocument::UpdateAllViews member function to coordinate updates to all views when any view changes the data.

You’ll usually use this option for simple form-based applications such as the Enroll tutorial application. AppWizard supports a convenient structure for such applications automatically.

A Document with File Support

Select the AppWizard database option “Both a database view and file support” when you have an alternative use for the document-related File menu commands and document serialization. For the data-access portion of your program, you can use the document in the same way as described in A Document Without File Support. You can use the document’s serialization capability, for example, to read and write a serialized user profile document that stores the user’s preferences or other useful information. For more ideas, see the article Serialization: Serialization vs. Database Input/Output.

AppWizard supports this option, but you must write the code that serializes the document. Store the serialized information in document data members.

Applications with No Document

You might sometimes want to write an application that uses neither documents nor views. Without documents, you store your data (such as a CRecordset or CDaoRecordset object) in your frame-window class or your application class. Any additional requirements depend on whether the application presents a user interface.

Database Support with a User Interface

If you have a user interface (other than, say, a console command-line interface), your application draws directly into the frame window’s client area rather than into a view. Such an application doesn’t use CRecordView, CDaoRecordView, CFormView, or CDialog for its main user interface (but it will normally use CDialog for ordinary dialogs).

Writing Applications Without Documents

AppWizard doesn’t support creating applications without documents, so you must write your own CWinApp-derived class and, if needed, also create a CFrameWnd or CMDIFrameWnd class. Override CWinApp::InitInstance and declare an application object as

CYourNameApp NEAR theApp;

The framework still supplies the message-map mechanism and many other features.

Database Support Separate from the User Interface

Some applications need either no user interface or only a minimal one. For example, suppose you’re writing:

  • An intermediate data-access object that other applications (clients) call for special processing of data between the application and the data source.

  • An application that processes data without user intervention, such as an application that moves data from one database format to another, or one that does calculations and performs batch updates.

Because there is no document that owns the CRecordset or CDaoRecordset object, you’ll probably want to store it as an embedded data member in your CWinApp-derived application class. Alternatives include:

  • Not keeping a permanent CRecordset or CDaoRecordset object at all. You can pass NULL to your recordset class constructors. In that case, the framework creates a temporary CDatabase or CDaoDatabase object using the information in the recordset’s GetDefaultConnect member function. This is the most likely alternative approach.

  • Making the CRecordset or CDaoRecordset object a global variable. This variable should be a pointer to a recordset object that you create dynamically in your CWinApp::InitInstance override. (This avoids attempting to construct the object before the framework is initialized.)

  • Using recordset objects as you would within the context of a document or a view. Create recordsets in the member functions of your application or frame-window objects.


Record

Home | Overview | How Do I | FAQ | ODBC Driver List

A record is a collection of data about a single entity, such as an account or a customer, stored in a table (a “row” of the table). A record consists of a group of contiguous columns (sometimes called fields) that contain data of various types. A set of records selected from a data source — often called a “result set” in database terms — is called a “recordset” in MFC. See the articles Recordset (ODBC) or DAO Recordset for more details.


Schema

Home | Overview | How Do I | FAQ | ODBC Driver List

A database schema describes the current structure of the tables and database views in the database. In general, ClassWizard assumes that the schema for the table(s) accessed by a recordset will not change, but the database classes can deal with some schema changes, such as adding, reordering, or deleting unbound columns. If a table changes, you can “refresh” your recordset for the table using ClassWizard’s Update Columns button and then recompile your application.

You can also supplement the code ClassWizard produces to deal with a database whose schema is not entirely known at compile time. For more information, see the article Recordset: Dynamically Binding Data Columns (ODBC).

To determine schema information with the MFC DAO classes, see the article DAO Tabledef: Examining a Database Schema at Run Time.

See Also SQL, Recordset (ODBC), ClassWizard Topics


Catalog Information

Home | Overview | How Do I | FAQ | ODBC Driver List

Information about the tables in a data source can include the names of tables and the columns in them, table privileges, names of primary and foreign keys, information about predefined queries or stored procedures, information about indexes on tables, and statistics about tables.

See the article Data Source: Determining the Schema of the Data Source (ODBC).

See also information about the ODBC “catalog functions” in the ODBC SDK Programmer’s Reference and the MFC Database sample program CATALOG.

Note In the MFC DAO classes, you can get catalog information as follows: Use CDaoDatabase::GetTableDefCount and CDaoDatabase::GetTableDefInfo to enumerate the tables in the database and obtain information for each table in a CDaoTableDefInfo structure. For more information, see the article DAO Collections: Obtaining Information About DAO Objects.


Record Views

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

To support form-based data-access applications, the class library provides class CRecordView and class CDaoRecordView. A “record view” is a form view object whose controls are mapped directly to the field data members of a recordset object (and indirectly to the corresponding columns in a query result or table on the data source). Like their base class CFormView, CRecordView and CDaoRecordView are based on a dialog template resource.

Form Uses

Forms are useful for a variety of data-access tasks:

  • Data entry

  • Read-only examination of data

  • Updating data

Further Reading About Record Views

The material in this group of articles applies to both the ODBC-based and the DAO-based classes. Use CRecordView for ODBC and CDaoRecordView for DAO.

Topics covered in this article include:

  • Features of record view classes

  • Data exchange for record views

  • Your role in working with a record view

  • Designing and creating a record view

  • Using a record view


Features of Record View Classes

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

You can do form-based data-access programming with class CFormView, but CRecordView and CDaoRecordView are generally better classes to derive from. In addition to their CFormView features, CRecordView and CDaoRecordView:

  • Provide dialog data exchange (DDX) between the form controls and the associated recordset object.

  • Handle Move First, Move Next, Move Previous, and Move Last commands for navigating through the records in the associated recordset object.

  • Update changes to the current record when the user moves to another record.

For more information about navigation, see the article Record Views: Supporting Navigation in a Record View.


Data Exchange for Record Views

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

When you use ClassWizard to map the controls in a record view’s dialog template resource to the fields of a recordset, the framework manages data exchange in both directions — from recordset to controls and from controls to recordset. Using the DDX mechanism means you don’t have to write the code to transfer data back and forth yourself. Make a few connections in ClassWizard and you’re done.

DDX for record views works in conjunction with:

  • RFX for recordsets of class CRecordset (ODBC)

  • DFX for recordsets of class CDaoRecordset (DAO)

Although they differ in implementation, at the interface level RFX and DFX are very similar data exchange mechanisms. The DAO version, DFX, is modeled closely on the earlier ODBC version, RFX. If you know how to use RFX, you know how to use DFX.

RFX and DFX move data between the current record of the data source and the field data members of a recordset object. DDX moves the data from the field data members to the controls in the form. This combination fills the form controls initially and as the user moves from record to record. It can also move updated data back to the recordset and then to the data source.

The following figure shows the relationship between DDX and RFX (or DFX) for record views.

Dialog Data Exchange and Record Field Exchange

For more information about DDX, see Dialog Data Exchange and Validation. For more information about RFX, see the article Record Field Exchange (RFX). For more information about DFX, see the article DAO Record Field Exchange (DFX).


Your Role in Working with a Record View

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The table below shows what you typically must do to work with a record view and what the framework does for you.

Working with a Record View: You and the Framework

You... | The framework...
Use the Visual C++ dialog editor to design the form. | Creates a dialog template resource with controls.
Use ClassWizard to create classes derived from CRecordView and CRecordset or from CDaoRecordView and CDaoRecordset. | Writes the classes for you.
Use ClassWizard to map record view controls to recordset field data members. | Provides DDX between the controls and the recordset fields.
 | Provides default command handlers for Move First, Move Last, Move Next, and Move Previous commands from menus or toolbar buttons.
 | Updates changes to the data source.
[Optional] Write code to fill list boxes or combo boxes or other controls with data from a second recordset. |
[Optional] Write code for any special validations. |
[Optional] Write code to add or delete records. |

Form-based programming is only one approach to working with a database. For information on applications using some other user interface, or no user interface, see the articles MFC: Using Database Classes with Documents and Views and MFC: Using Database Classes Without Documents and Views. For alternative approaches to displaying database records, see classes CListView and CTreeView as well as the MFC Database sample DAOVIEW.


Designing and Creating a Record View

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

You can create your record view class with either AppWizard or ClassWizard. If you use AppWizard, the wizard creates the record view class and a dialog template resource for it (without controls). You must use the Visual C++ dialog editor to add controls to the dialog template resource. On the other hand, if you use ClassWizard, you must first create the dialog template resource in the dialog editor, then open ClassWizard and create the record view class.

This information applies to both CRecordView and CDaoRecordView.

To create your record view with AppWizard

  • See the article AppWizard: Database Support

To design your form

  • See Using the Dialog Editor, in Visual C++ User’s Guide.

To create your record view class with ClassWizard

  • See the article ClassWizard: Creating a Database Form.

Tip For an example of an application with multiple record views on a database, see the ENROLL tutorial application, Step 4. The step is described in MFC Tutorial sample ENROLL.

The following articles explain additional details of using record views:

  • Record Views: Supporting Navigation in a Record View

  • Record Views: Using a Record View

  • Record Views: Filling a List Box from a Second Recordset

See Also ClassWizard: Mapping Form Controls to Recordset Fields, Recordset (ODBC)


Record Views: Supporting Navigation in a Record View

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to support movement from record to record in your record view, including information on:

  • Command handling for record scrolling commands.

  • User-interface update handlers for scrolling commands.

The information in this article applies to both CRecordView (ODBC) and CDaoRecordView (DAO).


Command Handlers for Record Scrolling

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Classes CRecordView and CDaoRecordView provide default command handling for the following standard commands:

  • ID_RECORD_MOVE_FIRST

  • ID_RECORD_MOVE_LAST

  • ID_RECORD_MOVE_NEXT

  • ID_RECORD_MOVE_PREV

The OnMove member function of classes CRecordView and CDaoRecordView provides default command handling for all four commands, which move from record to record. As these commands are issued, RFX (or DFX) loads the new record into the recordset’s fields and DDX moves the values into the record form’s controls. For information about RFX, see the article Record Field Exchange (RFX). For information about DFX, see the article DAO Record Field Exchange (DFX).

Important Be sure to use these standard command IDs for any user-interface objects associated with the standard record navigation commands.


User-Interface Updating for Record Views

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

CRecordView and CDaoRecordView also provide default user-interface update handlers for the navigation commands. These handlers automate enabling and disabling the user-interface objects — menu items and toolbar buttons. AppWizard supplies standard menus and, if you choose the AppWizard “Dockable Toolbar” option, a set of toolbar buttons for the commands. If you create a record view class with ClassWizard, you may want to add similar user-interface objects to your application.

To create menu resources with the menu editor

  • Using the information on using the menu editor in Visual C++ User’s Guide, create your own menu with the same four commands.

To create toolbar buttons with the graphics editor

  • Using the information on using the toolbar editor in Visual C++ User’s Guide, edit the toolbar resource to add toolbar buttons for your record navigation commands.

For an example of these steps, see Constructing the User Interface in Tutorials.

See Also Record Views: Using a Record View


Record Views: Using a Record View

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how you might commonly customize the default code for record views that the wizard writes for you. Typically, you’ll want to constrain the record selection with a filter or parameters, perhaps sort the records, or customize the SQL statement.

This information applies to both CRecordView (ODBC) and CDaoRecordView (DAO).

Using CRecordView or CDaoRecordView is much the same as using CFormView. The basic approach is to use the record view to display and perhaps update the records of a single recordset. Beyond that, you might want to use other recordsets as well, as discussed in the article Record Views: Filling a List Box from a Second Recordset.


Record View Code Created by AppWizard

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

ClassWizard (or AppWizard) overrides the view’s OnInitialUpdate and OnGetRecordset member functions. After the framework creates the frame window, document, and view, it calls OnInitialUpdate to initialize the view. OnInitialUpdate obtains a pointer to the recordset from the document. A call to the base class CView::OnInitialUpdate function opens the recordset. The following code shows this process for a CRecordView ? the code for a CDaoRecordView is similar:

void CSectionForm::OnInitialUpdate()
{
   m_pSet = &GetDocument()->m_sectionSet;
   CRecordView::OnInitialUpdate();
}

When the recordset opens, it selects records. CRecordset::Open or CDaoRecordset::Open makes the first record the current record, and DDX moves data from the recordset’s field data members to the corresponding form controls in the view. For more information about RFX, see the article Record Field Exchange (RFX). For more information about DFX, see the article DAO Record Field Exchange (DFX). For more information about DDX, see Dialog Data Exchange and Validation. For details of the document/view creation process, see Using the Classes to Write Applications for Windows.

Important You should give your end users the capability to refresh the record view controls from the recordset. Without this capability, if a user changes a control’s value to an illegal value, he or she could be permanently stuck on the current record. To refresh the controls, you call the CWnd member function UpdateData with a parameter of FALSE. For an example, see Step 3 in the ENROLL tutorial — look at the OnRecordAdd member function in file SECTFORM.CPP. The tutorial begins in Creating a Database Application in Tutorials.


Changes You Might Make to the Default Code

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

ClassWizard writes a recordset class for you that simply selects all records in a single table. You’ll often want to modify that behavior in one or more of the following ways:

  • Set a filter and/or a sort order for the recordset. Do this in OnInitialUpdate after the recordset object is constructed but before its Open member function is called. See the articles Recordset: Filtering Records (ODBC) and Recordset: Sorting Records (ODBC) for details. For DAO, see the article DAO Queries: Filtering and Parameterizing Queries. For an example, see the OnInitialUpdate member function in the file SECTFORM.CPP in the MFC Tutorial sample ENROLL, Step 2.

  • Parameterize the recordset. Specify the actual run-time parameter value after the filter. See the article Recordset: Parameterizing a Recordset (ODBC) or DAO Queries: Filtering and Parameterizing Queries for details.

  • Pass a customized SQL string to the Open member function. For a discussion of what you can accomplish with this technique:
    • For ODBC, see the article SQL: Customizing Your Recordset’s SQL Statement (ODBC).

    • For DAO, see the article DAO Queries.


Record Views: Filling a List Box from a Second Recordset

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

By default, a record view is associated with a single recordset object, whose fields are mapped to the record view’s controls. Sometimes you will want to put a list box or combo box control in your record view and fill it with values from a second recordset object. The user can use the list box to select a new category of information to display in the record view. This article explains how and when to do that.

Tip Be aware that filling a combo box or list box from a data source might be slow. Take precautions against trying to fill a control from a recordset with a large number of records.

For example, the ENROLL tutorial in Tutorials uses a CRecordView, CSectionForm, to display information about sections of college courses. (For DAO tutorial purposes, follow the ODBC ENROLL tutorial except for Step 1.) ENROLL binds the form’s controls to the field data members of a recordset of class CSectionSet. CSectionForm’s combo box control is filled from a second recordset of class CCourseSet that contains a record for each course offered at the school. When the user selects a new course in the combo box, the record view requeries the CSectionSet recordset to get the sections for the selected course. See the MFC Tutorial sample ENROLL. Step 2 adds the combo box.

The model for this article, then, consists of a primary recordset that fills the controls of your form, while a secondary recordset fills a list box or combo box. Selecting a string from the list box causes your program to requery the primary recordset based on what was selected. The procedure below uses a combo box but applies equally to a list box.

To fill a combo box or list box from a second recordset

  1. Create the recordset object (CRecordset for ODBC, CDaoRecordset for DAO).

  2. Obtain a pointer to the CComboBox object for the combo box control.

  3. Empty the combo box of any previous contents.

  4. Move through all records in the recordset, calling CComboBox::AddString for each string from the current record you want to add to the combo box.

  5. Initialize the selection in the combo box.

The code in the OnInitialUpdate member function of class CSectionForm in the MFC Tutorial sample ENROLL illustrates the procedure. The following excerpt shows how the combo box is filled by extracting a course ID value from each record in the recordset pointed to by pCourses. (The code for DAO is quite similar.)

void CSectionForm::OnInitialUpdate()
{
    // ...

    // Fill the combo box with all of the courses
    CENROLLDoc* pDoc = GetDocument();
    if (!pDoc->m_courseSet.Open())
        return;

    // ...

    m_ctlCourseList.ResetContent();
    if (pDoc->m_courseSet.IsOpen())
    {
        while (!pDoc->m_courseSet.IsEOF() )
        {
            m_ctlCourseList.AddString(
                pDoc->m_courseSet.m_CourseID);
            pDoc->m_courseSet.MoveNext();
        }
    }
    m_ctlCourseList.SetCurSel(0);
}

This function uses a second recordset, m_courseSet, which contains a record for each course offered, and a CComboBox control, m_ctlCourseList, which is stored in the record view class.

The function gets m_courseSet from the document and opens it. Then it empties m_ctlCourseList and scrolls through m_courseSet. For each record, the function calls the combo box’s AddString member function to add the course ID value from the record. Finally, the code sets the combo box’s selection.


Database Topics (DAO)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The Microsoft Foundation Class Library (MFC) supplies classes for programming with Data Access Objects (DAO). These classes are distinct from the older MFC classes supplied for programming with Open Database Connectivity (ODBC).

Frequently Asked Questions About MFC Database Support

  • What data sources can I access with DAO and ODBC?

  • Can I call DAO or ODBC APIs directly while using the classes?

  • What ODBC drivers are provided?

  • What ODBC drivers are installed by default?

What do you want to know more about?

  • Data access objects (DAO)

  • DAO and MFC

  • Writing a database application

  • Database tasks with DAO

  • Improving performance with DAO

  • Working with external data sources via DAO

  • DAO queries and querydefs

  • DAO record field exchange (DFX)

  • DAO recordsets

  • DAO tabledefs

  • DAO workspaces

  • How the database classes work with MFC’s document/view architecture

See Also DAO: Where Is...


Data Access Objects (DAO)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Data Access Objects (DAO) provide a framework for using code to create and manipulate databases. DAO supplies a hierarchical set of objects that use the Microsoft Jet database engine to access data and database structure in:

  • Microsoft Jet (.MDB) databases

  • ODBC data sources, using an ODBC driver

  • Installable ISAM databases, such as dBASE®, Paradox™ and Microsoft FoxPro which the database engine can read directly

To begin learning about the DAO technology, see the topic "Data Access Objects Overview" in DAO Help.

For information about the MFC classes that encapsulate DAO, begin with the articles Database Topics (DAO) and DAO and MFC.

Tip From any of the MFC help topics in this documentation set, you can get to a topic called DAO: Where Is..., which helps you navigate online to the topics that you need. The topic is always available via the See Also list at the bottom of the topic window.

See Also DAO: Where Is...


DAO and MFC

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes MFC’s implementation of Microsoft Data Access Objects (DAO). Topics covered include:

  • How MFC Encapsulates DAO

  • Mapping of DAO objects to MFC classes

  • Key differences between MFC and DAO

  • Further reading about the MFC DAO classes

Note Whether you use the MFC DAO classes or the MFC ODBC classes depends on your situation and your needs. For a discussion of the differences between the two and guidance on choosing one, see the article Database Topics (DAO).

Caution DAO is not supported on Win32s. Further, DAO 3.x is not thread-safe. You should use DAO only in the primary thread of an application.

How MFC Encapsulates DAO

The MFC DAO classes treat DAO much as the MFC classes for programming Windows treat the Windows API: MFC encapsulates, or "wraps," DAO functionality in a number of classes that correspond closely to DAO objects. Class CDaoWorkspace encapsulates the DAO workspace object, class CDaoRecordset encapsulates the DAO recordset object, class CDaoDatabase encapsulates the DAO database object, and so on.

MFC's encapsulation of DAO is thorough, but it is not completely one-for-one. Most major DAO objects do correspond to an MFC class, and the classes supply generally thorough access to the underlying DAO object's properties and methods. But some DAO objects, including fields, indexes, parameters, and relations, do not. Instead, the appropriate MFC class provides an interface, via member functions, through which you can access, for example:

  • The fields of a recordset object

  • The indexes or fields of a table

  • The parameters of a querydef

  • The relations defined between tables in a database

Mapping of DAO Objects to MFC Classes

The following tables show how DAO objects correspond to MFC objects. MFC Classes and Corresponding DAO Objects shows the MFC classes and the DAO objects they encapsulate. How MFC Manages DAO Objects Not Mapped to Classes shows how MFC deals with DAO objects that do not map directly to an MFC class.

MFC Classes and Corresponding DAO Objects

Class | DAO object | Remarks
CDaoWorkspace | Workspace | Manages a transaction space and provides access to the database engine.
CDaoDatabase | Database | Represents a connection to a database.
CDaoTableDef | Tabledef | Used to examine and manipulate the structure of a table.
CDaoQueryDef | Querydef | Used to store queries in a database. You can create recordsets from a querydef or use it to execute action or SQL pass-through queries.
CDaoRecordset | Recordset | Used to manage a result set, a set of records based on a table or selected by a query.
CDaoException | Error | MFC responds to all DAO errors by throwing exceptions of this type.
CDaoFieldExchange | None | Manages exchange of data between a record in the database and the field data members of a recordset.

How MFC Manages DAO Objects Not Mapped to Classes

DAO object | How MFC manages it
Field | Objects of classes CDaoTableDef and CDaoRecordset encapsulate fields and supply member functions for adding them, deleting them, and examining them.
Index | Objects of classes CDaoTableDef and CDaoRecordset encapsulate indexes and supply member functions for managing them. Tabledefs can add, delete, and examine indexes. Tabledefs and recordsets can set or get the currently active index.
Parameter | Objects of class CDaoQueryDef encapsulate parameters and supply member functions for adding them, deleting them, examining them, and getting and setting their values.
Relation | Objects of class CDaoDatabase encapsulate relations and supply member functions for adding them, deleting them, and examining them.

DAO Objects Not Exposed in MFC

MFC and DAO do not supply abstractions for some objects used within Microsoft Access: Application, Container, Control, Debug, Document, Form, Module, Report, Screen, and Section. If you create a Microsoft Access database and manipulate it from an MFC application, you can’t access those objects through code.

MFC doesn’t supply classes or interfaces to the DAO group and user objects ? to work with DAO security, you must write your own code.

MFC also doesn’t encapsulate DAO property objects, except that the MFC DAO classes do give you access to the properties of all exposed objects.

MFC does give you access to DAO’s DBEngine object, through class CDaoWorkspace.

Accessing the Unexposed DAO Objects

The unexposed objects listed above can be accessed in two ways:

  • Outside the MFC classes by using the non-MFC C++ classes provided in the DAO SDK, located in the \DAOSDK directory on the Visual C++ CD.

  • Inside the MFC classes by calling DAO directly through a DAO interface pointer supplied by one of the MFC classes. For information, see Technical Note 54.

Key Differences Between MFC and DAO

MFC's version of data access objects differs from the underlying structure of DAO in some ways.

How MFC Accesses the Database Engine

DAO has a DBEngine object that represents the Microsoft Jet database engine. The DBEngine object provides properties and methods you can use to configure the database engine.

In MFC, there is no DBEngine object. Access to important properties of the database engine is supplied via class CDaoWorkspace. To set or get these properties, call any of the static member functions of CDaoWorkspace. For more information, see the articles DAO Workspace: The Database Engine and DAO Workspace: Accessing Properties of the Database Engine.

MFC Flattening of the DAO Object Hierarchy

Because MFC doesn't supply a class for every DAO object, the effect is that the DAO object hierarchy is somewhat "flattened" in MFC. The main examples of this flattening are:

  • Putting access to the database engine in class CDaoWorkspace rather than in a database engine class.

  • Encapsulating DAO field, index, parameter, and relation objects inside the classes that represent their owning objects. For example, access to fields is encapsulated in classes CDaoTableDef and CDaoRecordset. For information, see the table How MFC Manages DAO Objects Not Mapped to Classes.

MFC and DAO Security

MFC does not encapsulate the DAO user and group objects in any way, which means that MFC doesn't provide DAO's security functionality.

You can still use DAO security from your MFC applications, but you will have to call DAO directly, using the m_pDAOWorkspace data member of class CDaoWorkspace. That member is a pointer to an interface that gives access to a DAO workspace object's methods and properties. For information about calling DAO directly, see Technical Note 54.

Tip The DAO Software Development Kit (SDK) supplies its own set of C++ classes (not compatible with MFC) for working with DAO. You can use these classes, if you wish, by installing the DAO SDK using \DAOSDK\Disk1\Setup.exe on the Visual C++ CD. These classes provide an additional source of examples for using DAO from C++.

MFC does allow password protection via various MFC classes. For example, when you create a CDaoWorkspace object, you can specify a password to protect the database(s) that the workspace contains. To use this functionality, a SYSTEM.MDW file must be available to the database engine on the machine running your application. If no SYSTEM.MDW file is available to the database engine, your application cannot use any of the security features. For information about the SYSTEM.MDW file, see the topic "Permissions Property" in DAO Help.

Further Reading About the MFC DAO Classes

To learn more about using the MFC DAO classes, see the following articles (in the order listed here):

  • DAO: Writing a Database Application

  • DAO: Database Tasks

  • DAO: Creating, Opening, and Closing DAO Objects

  • DAO Workspace

  • DAO Database

  • DAO Database: Using Workspaces and Databases

  • DAO Recordset

  • DAO Record Field Exchange (DFX)

  • DAO Querydef

  • DAO Tabledef

  • DAO Workspace: Managing Transactions

  • DAO Collections

  • DAO External: Working with External Data Sources (primarily ODBC)

  • DAO Workspace: The Database Engine

  • DAO: Using DAO in DLLs

  • Overview: Creating a Program That Supports a Database

  • ClassWizard: Database Support

  • Exceptions: Database Exceptions

  • Record Views

Tip From any of the MFC help topics in this documentation set, you can get to a topic called DAO: Where Is..., which helps you navigate online to the topics that you need. The topic is always available via the See Also button in the topic window.

See Also DAO: Where Is...


DAO: Where Is...

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article will help you locate topics of interest in the MFC DAO documentation and in the DAO Help topics. This article is organized as follows:

  • DAO Overviews

  • DAO Objects

  • Information By Topic

  • Key DAO Help Topics

Documentation for the MFC DAO classes consists of two components:

  • MFC-specific: MFC classes in the Class Library Reference and MFC encyclopedia articles in Visual C++ Programmer’s Guide. The articles all begin with the “DAO” prefix.

  • DAO-specific: Topics from the DAO Help files shipped with products such as Microsoft Office. These topics have been incorporated into the online documentation, but note that they are oriented toward the Basic programming language. They are included to provide DAO-specific details in areas where MFC neither modifies nor adds to DAO functionality.

DAO Overviews

For overviews and general information about MFC DAO, see:

  • Database Topics (DAO)

  • DAO and MFC

  • Data Access Objects (DAO)

  • DAO: Writing a Database Application

  • DAO: Database Tasks

DAO Objects

DAO consists of a number of objects. Here’s where to find information about each object type:

Where to find information about DAO objects

DAO Help topics | MFC class | MFC Help topics
Database Object | CDaoDatabase | DAO Database
Error Object | CDaoException | CDaoException
Querydef Object | CDaoQueryDef | DAO Querydef
Recordset Object | CDaoRecordset | DAO Recordset
Tabledef Object | CDaoTableDef | DAO Tabledef
Workspace Object | CDaoWorkspace | DAO Workspace

See Also DAO Database: Using Workspaces and Databases, DAO: Creating, Opening, and Closing DAO Objects, DAO: Accessing Implicit MFC DAO Objects, DAO External: Working with External Data Sources, DAO Queries, DAO Record Field Exchange (DFX)

Information By Topic

To simplify locating the article(s) that discuss a particular topic area, use the following table:

Where to look for...

Topic | Location
Action queries | DAO Querydef: Action Queries and SQL Pass-Through Queries
Adding records | DAO Recordset: Recordset Operations
Aggregate records | DAO Recordset: Using Aggregate SQL Functions with MFC DAO Classes
Application design options | DAO: Writing a Database Application
Attaching tables | DAO External: Working with External Data Sources
Buffering records | DAO Record Field Exchange: Double Buffering Records
Calling DAO directly | Can I Call DAO or ODBC Directly?
CDaoXInfo structures | DAO Collections: Obtaining Information About DAO Objects
Closing DAO objects | DAO: Creating, Opening, and Closing DAO Objects
Collections in DAO | DAO Collections
Console applications and DAO | DAO: Database Application Design Options
Creating DAO objects | DAO: Creating, Opening, and Closing DAO Objects
DAO objects not mapped to classes | DAO and MFC
DAO vs. ODBC | Should I Use DAO or ODBC?
Data definition language (DDL) | Database Definition and Manipulation
Database engine (Jet) | DAO Workspace: The Database Engine
Data types | DFX Data Types in DAO Record Field Exchange: Using the DFX Functions
DBMS targets | DAO: Writing a Database Application What Data Sources Can You Access with DAO and ODBC?
Default workspace | DAO Workspace: Explicitly Opening the Default Workspace
Definition of DAO | What Are DAO and ODBC?
DLLs, DAO in | DAO: Database Application Design Options DAO: Using DAO in DLLs
Document/view architecture | DAO: Writing a Database Application
Documentation | More Information About the DAO and ODBC Classes
Double buffering records | DAO Record Field Exchange: Double Buffering Records
Engine initialization | DAO Workspace: The Database Engine
External data sources, list | DAO External: Working with External Data Sources
Filtering recordsets | DAO Queries: Filtering and Parameterizing Queries
Finding | DAO Recordset: Recordset Navigation
Forms | Record Views
How MFC encapsulates DAO | DAO and MFC
Installing DAO | Installing MFC Database Support
ISAM databases, list | Database Topics (DAO)
Jet database engine | DAO Workspace: The Database Engine
Multithreading and DAO | DAO: Database Application Design Options
Navigating in a recordset | DAO Recordset: Recordset Navigation
ODBC data sources | DAO External: Working with External Data Sources
ODBC drivers | ODBC Driver List
ODBC vs. DAO | What Are DAO and ODBC? Should I Use DAO or ODBC?
ActiveX controls, DAO in | DAO: Database Application Design Options
Opening DAO objects | DAO: Creating, Opening, and Closing DAO Objects
Parameterizing queries | DAO Queries: Filtering and Parameterizing Queries
Pass-through queries | DAO Querydef: Action Queries and SQL Pass-Through Queries
Performance | DAO External: Improving Performance with External Data Sources
Programming model | What Is the MFC Database Programming Model?
Queries | DAO Queries
Querydefs | DAO Querydef
Record Field Exchange (DFX) | DAO Record Field Exchange (DFX)
Recordsets | DAO Recordset
Scrolling | DAO Recordset: Recordset Navigation
Security | DAO and MFC
Seeking | DAO Recordset: Recordset Navigation
SQL | DAO Queries: SQL for DAO
Tabledefs | DAO Tabledef
Task-oriented topics | DAO: Database Tasks
Transactions | DAO Workspace: Managing Transactions
Updating data | DAO Recordset: Recordset Operations
Views of DAO data | DAO: Writing a Database Application
When to use database classes | When Should I Use the Database Classes?
Workspace, typical scenario | DAO Database: Using Workspaces and Databases
Writing a database application | DAO: Writing a Database Application

See Also DAO Database: Using Workspaces and Databases, DAO: Creating, Opening, and Closing DAO Objects, DAO: Accessing Implicit MFC DAO Objects, DAO External: Working with External Data Sources, DAO Queries, DAO Record Field Exchange (DFX), Database Topics (DAO), DAO and MFC

Key DAO Help Topics

The following topics are part of DAO Help and are not MFC-specific. To use them, you must open the DAO SDK help file, which is not part of the online documentation.

  • Data Access Object Hierarchy

  • Data Access Objects and Collections Reference

  • Using Data Access

  • Trappable Data Access Errors

  • Microsoft Jet Database Engine SQL Data Types

  • Microsoft Jet Database Engine SQL Reserved Words

  • Equivalent ANSI SQL Data Types

  • SQL Aggregate Functions


DAO: Writing a Database Application

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This family of articles discusses writing database applications with the MFC DAO classes. Other articles focus on various parts of the process; this article looks at using DAO from an application design standpoint.

In This Article

This article considers:

  • What is a database application?

  • First steps in writing your MFC DAO application

  • Data viewing choices

  • Documents and views with DAO

  • DBMS choices

Other Articles in the Article Family on the Process

The following additional articles discuss parts of the design and development process (in recommended reading order):

  • DAO: Database Application Design Options

  • DAO: Steps in Writing MFC DAO Applications

What Is a Database Application?

Database applications obtain and manipulate data from a database managed by a database management system (DBMS). Typical database applications include programs for data input, data viewing, and batch processing of data.

Of course, there is no one kind of database application. There is a wide range from simple data entry or data viewing applications to complex client/server applications.

Beyond that, applications of any sort might use a database rather than disk-based files for input/output. For example, an e-mail client program that you use to read your mail doesn’t feel like a traditional database application, but it might use a database to store addresses, messages, and other information. In any case, the MFC DAO classes supply abstractions that you can use to write any kind of database application.

First Steps in Writing Your MFC DAO Application

To begin, you must make two fundamental decisions:

  • How do you want to display data in your application: in a form, as a list, some other way, or not at all.

  • What database management system(s) (DBMSs) do you intend to target?

Your decisions determine how your application fits into MFC's document/view architecture and how appropriate the DAO classes are for your application. Your answers also help determine the selections you make when you run AppWizard to begin constructing your application.

Data Viewing Choices

MFC supplies varying degrees of support for different viewing choices:

  • Displaying one record at a time in a form.

    AppWizard will create a CDaoRecordView-derived class for you and connect it to a CDaoRecordset based on a table you specify. This makes it easy to create simple form-based applications.

  • Displaying multiple records at a time.

    While AppWizard doesn't give any special help for this option, you can fairly easily connect a CDaoRecordset to a CListView or CTreeView. For examples, see the MFC Database sample DAOVIEW.

  • Displaying multiple views of the data simultaneously, either in separate windows or in panes of a splitter window.

Documents and Views with DAO

Do you need the MFC document/view architecture? The simplest architecture for MFC applications is to manage your data within an MFC document object and manage displaying that data separately in a view object. You aren't limited to this structure, though. Other options include:

  • Using a view object but treating the document as an unused appendage.

    You can make your data structures — mainly your CDaoDatabase and CDaoRecordset objects — members of your CView-derived class rather than of a CDocument-derived class. Database applications typically don't need MFC's serialization mechanism, which is the primary feature of CDocument.

    A particularly strong argument for using MFC’s document/view architecture is the ability to manage multiple views of your data through the document. CDocument has an UpdateAllViews member function that you can call to synchronize your views as data displayed in them changes. This is as useful in database applications as in any other kind of application.

  • Drawing your data directly into the client area of a CFrameWnd-derived class.

    You can handle Windows messages in the frame window and thus dispense with the view and the document. If you use a view, you can't just strip the document code from your application, but if you use neither view nor document, you can remove (or ignore) both the view code and the document code. In this case, you can store your CDaoDatabase and CDaoRecordset objects in the frame window class.

  • Basing your application on a dialog box.

    AppWizard supports this approach, and you can store your CDaoDatabase object(s) as members of your CDialog-derived class.

For related information, see the articles MFC: Using Database Classes with Documents and Views and MFC: Using Database Classes Without Documents and Views.

DBMS Choices

DAO is based on the Microsoft Jet database engine. Thus, DAO is optimally suited for working with Microsoft Jet (.MDB) databases. DAO also supports accessing external databases, including certain installable ISAM databases (which the database engine can read directly) and ODBC data sources. This means you can write DBMS-independent applications with DAO, targeting any data source that the Microsoft Jet database engine can read directly or for which your users will have the appropriate ODBC driver.

Note, however, that in general it is more efficient, with DAO, to attach ODBC data source tables to a Microsoft Jet database than it is to access the external data source directly. If your application is targeted on an external data source such as Microsoft SQL Server or Oracle, you might want to consider using the MFC ODBC classes instead of DAO.

For related information, see the articles Database Topics (DAO) and DAO External: Working with External Data Sources.

See Also DAO: Where Is..., DAO: Database Tasks, DAO: Database Application Design Options, DAO: Steps in Writing MFC DAO Applications, MFC: Using Database Classes with Documents and Views, MFC: Using Database Classes Without Documents and Views.


DAO: Database Application Design Options

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article continues the discussion begun in the article DAO: Writing a Database Application. The article DAO: Steps in Writing MFC DAO Applications completes the discussion. Those articles discuss the decisions you need to make before you run AppWizard and the steps involved in creating your starter application.

Topics covered include:

  • Application design examples

  • DAO in DLLs, multithreaded applications, and ActiveX controls

Application Design Examples

This article gives examples to suggest some of the ways you might organize your application. Sample applications mentioned in the list are available under Visual C++ Programmer’s Guide/Samples in the documentation.

Examples:

  • An application that uses a single form to view one record at a time.

    This approach might be suitable for simple data entry or data viewing applications.

    Let AppWizard create the CDaoRecordView and CDaoRecordset classes for you. Then design the form in the Visual C++ dialog editor.

    In this scenario, a single CDaoRecordset object persists for a session, and it uses an implicitly created CDaoDatabase object. The recordset, a data member of the CDaoRecordView class called m_pSet, contains all records in a table or all records returned by a query. The view lets the user scroll through the records one at a time.

    For an example, see Step 1 of the MFC Database sample DAOENROL.

  • A similar single-form application that displays one record at a time but also uses a second recordset to fill a list box or combo box.

    Let AppWizard create the CDaoRecordView and a CDaoRecordset to control which record is currently displayed in the form's general controls.

    Use ClassWizard to create a second CDaoRecordset based on the table or query that fills the list or combo box.

    For a view of how this works, see the MFC Database sample ENROLL for the MFC ODBC classes. You’ll have to translate some of the code, but the model is the same in DAO, and most of the code is very similar as well.

    Create additional recordsets to fill more list or combo boxes as needed.

  • An application based on multiple forms.

    Perhaps the forms appear in separate windows or as panes in a splitter window. Let AppWizard create the first CDaoRecordView and CDaoRecordset. Then use ClassWizard to add more of each.

  • A bulk data processing application, where no view is required.

    In AppWizard, select basic database support, without a view. A dialog-based application might be appropriate for this need.

    Use ClassWizard to create a CDaoRecordset class for each end of the migration. Then write code to use one recordset for input and the other for output. Perform any necessary data manipulation between the two recordsets. Note that you can use the MFC DAO classes in console applications. For more information, see DAO in DLLs, Multithreaded Applications, and ActiveX Controls.

  • An application that displays multiple records at a time, perhaps in a CListView or a CTreeView.

    Use AppWizard to specify the view class on which to base your application-specific view. You can also use multiple views, perhaps displayed as panes of a splitter window.

    For an example, see the MFC Database sample DAOVIEW.

For information about splitter windows, see Enhancing Views in the Scribble tutorial. For information about using multiple views in general, see Multiple Document Types, Views, and Frame Windows.

DAO in DLLs, Multithreaded Applications, and ActiveX Controls

This topic discusses the MFC DAO classes with respect to support for using the MFC DAO classes:

  • In dynamic link libraries (DLLs)

  • In ActiveX controls

  • In multithreaded applications

  • In console applications

  • In applications built for Unicode or double-byte character systems (DBCS)

You can use the MFC DAO classes in any DLL, as well as in ActiveX controls. For more information about using the MFC DAO classes in a DLL, see the article DAO: Using DAO in DLLs.

DAO itself is not multithreaded, so you can’t use the MFC DAO classes in multiple threads. Confine your DAO code to a single thread of execution.

Depending on what MFC functionality you call, you should be able to use the MFC DAO classes in console applications as well. Make sure the application uses no graphical user-interface elements. For example, if you’re using an ODBC data source and you supply incomplete connection information, ODBC attempts to display a dialog box for the missing information. Avoid this situation in your console applications.

The MFC DAO classes are fully enabled for Unicode and DBCS.

See Also DAO: Where Is..., DAO: Database Tasks, DAO: Writing a Database Application, DAO: Steps in Writing MFC DAO Applications, MFC: Using Database Classes with Documents and Views, MFC: Using Database Classes Without Documents and Views


DAO: Steps in Writing MFC DAO Applications

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article continues the discussion begun in the articles DAO: Writing a Database Application and DAO: Database Application Design Options. Those articles describe application design choices. This article explains the steps you take to develop your application.

Once you've made your initial design decisions, follow these steps:

  1. Run AppWizard to create a skeleton application.

    On the databases page, select the database options you want. It is at this stage that you specify a CDaoRecordView if you want a form-based application.

    When you open the Database Options dialog box, select DAO rather than ODBC. The result is an application with the right include directives and libraries for using the DAO classes. The wizard prompts you to specify the name of a Microsoft Jet (.MDB) database.

  2. If needed, add a CDaoDatabase object for each database your application can open simultaneously.

    If these objects need to persist for long periods, declare them as data members of one of your classes that point to CDaoDatabase objects you create on the heap — the document is a good choice.

    If they are to persist for long, create the objects with the new operator, perhaps in your document's OnNewDocument member function or in a command-handler function for a menu command.

  3. Use your CDaoDatabase object(s) to create CDaoRecordset objects that represent queries.

    If you prefer to create your recordsets on the fly, you can omit the CDaoDatabase object(s). MFC will implicitly create a CDaoDatabase object if you don't supply a pointer to one in the recordset's Open call.

    You can create your recordsets on the heap, or you can create them as local variables in a function.

See Also DAO: Where Is..., DAO Recordset, Record Views, DAO: Database Tasks, DAO: Database Application Design Options, MFC: Using Database Classes with Documents and Views, MFC: Using Database Classes Without Documents and Views


DAO: Database Tasks

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article points you to other articles about performing common database tasks. The following table lists the tasks and articles.

Articles About Common Database Tasks

 | For information about... | See...
Applications | Writing a database application | DAO: Writing a Database Application
 | Accessing the database engine | DAO Workspace: Accessing Properties of the Database Engine DAO Workspace: The Database Engine
Creating Objects | Creating DAO objects | DAO: Creating, Opening, and Closing DAO Objects
Opening Objects | Opening DAO objects | DAO: Creating, Opening, and Closing DAO Objects
Closing Objects | Closing DAO objects | DAO: Creating, Opening, and Closing DAO Objects
Collections (DAO) | Accessing collections | DAO Collections
 | Obtaining information about objects in collections | DAO Collections: Obtaining Information About DAO Objects
Databases | Creating an .MDB database | DAO Database
 | Examining the schema of a database | DAO Tabledef DAO Tabledef: Examining a Database Schema at Run Time
 | Working with multiple databases | DAO Workspace
ODBC | Working with ODBC data sources | DAO External: Working with External Data Sources
Queries Recordsets | Selecting records | DAO Queries DAO Recordset DAO Recordset: Creating Recordsets DAO Queries: Filtering and Parameterizing Queries
 | Binding records dynamically | DAO Recordset: Binding Records Dynamically
 | Updating records | DAO Recordset: Recordset Operations
 | Defining stored queries | DAO Querydef
 | Navigating in a recordset | DAO Recordset: Recordset Navigation
Record Field Exchange | Using DFX to exchange data between the database and a recordset's field data members | DAO Record Field Exchange (DFX)
 | Moving data between a recordset and the controls on a form | Dialog Data Exchange and Validation
SQL | Using SQL with DAO | DAO Queries: SQL for DAO
Tables | Adding or deleting a table | DAO Tabledef: Using Tabledefs
 | Adding or deleting a table field | DAO Tabledef: Using Tabledefs
 | Adding or deleting a table index | DAO Tabledef: Using Tabledefs
Transactions | Managing database transactions | DAO Workspace: Managing Transactions DAO Workspace: Opening a Separate Transaction Space

See Also DAO: Where Is...


DAO: Creating, Opening, and Closing DAO Objects

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This family of articles explains what it means to “open” or “create” an MFC DAO object and what it means to “close” the object when you finish with it.

This article discusses how MFC objects are constructed and points to related general articles. The following additional articles discuss the Create, Open, and Close actions:

  • DAO: Creating DAO Objects

  • DAO: Opening DAO Objects

  • DAO: Closing DAO Objects

Two-Stage Construction of MFC DAO Objects

As with most MFC objects, you use a two-stage process to create the MFC object and put it into an open state.

Creating a New Object

To create a new MFC DAO object

  1. Construct the object (on the stack or on the heap, using the new operator).

  2. Call the object’s Create member function.

  3. In some cases, call the Append member function to add the object to the appropriate DAO collection.
    • Database objects are appended to the collection automatically upon creation. CDaoDatabase has no Append member function.

    • Workspace and querydef objects can be created as temporary objects. To learn how to create a temporary object, see its class overview. Temporary objects are not appended.

    • Objects that you want to persist between database engine sessions should be appended.

For details, see each class constructor in the Class Library Reference.

Opening an Existing Object

To construct and open an MFC DAO Object

  1. Construct the object (on the stack or on the heap, using the new operator).

  2. Call the object's Open member function.

Before you call Open, the object is typically uninitialized and unusable (for exceptions, see CDaoWorkspace::Open). This example shows how to construct and open a CDaoRecordset object:

// CDelinquentSet is derived from CDaoRecordset
// Construct the recordset using the default database
CDelinquentSet rsDelinquentAccts;

// Set the object's properties as needed, then...
rsDelinquentAccts.Open( );  // Using default parameters

Related Articles on Creating, Opening, and Closing Objects

For related information, see the following articles:

  • DAO: Accessing Implicit MFC DAO Objects

  • DAO Workspace: Explicitly Opening the Default Workspace

  • DAO Workspace: Opening a Separate Transaction Space

  • DAO Workspace: Accessing Properties of the Database Engine

See Also CDaoWorkspace::Open, CDaoWorkspace::Close, CDaoDatabase::Open, CDaoDatabase::Close, CDaoTableDef::Open, CDaoTableDef::Close, CDaoQueryDef::Open, CDaoQueryDef::Close, CDaoRecordset::Open, CDaoRecordset::Close, CDaoDatabase::Create, CDaoQueryDef::Create, CDaoTableDef::Create, CDaoWorkspace::Create


DAO: Creating DAO Objects

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

All of the MFC DAO classes, except CDaoRecordset, have member functions for creating new objects. Creation means somewhat different things for different DAO objects. Topics covered include:

  • Create member functions

  • Meaning of the Create action for different DAO objects

Create Member Functions

The following objects have Create member functions:

  • CDaoWorkspace::Create

  • CDaoDatabase::Create

  • CDaoQueryDef::Create

  • DaoTableDef::Create

In addition, some objects supply member functions for creating subordinate objects, as shown in the table “Creating DAO Objects without MFC Classes” below. MFC does not supply classes for these subordinate objects. Instead, it supplies access to them through member functions of the appropriate containing class.

Creating DAO Objects without MFC Classes

Owning class | Creation functions
CDaoDatabase | CreateRelation
CDaoTableDef | CreateField, CreateIndex

Meaning of the Create Action for Different DAO Objects

The concept of “create” has different meanings for different MFC DAO objects, as shown in the following table.

Meaning of Create for DAO Objects

Object | Meaning
Database | Creates a new Microsoft Jet database; that is, creates the .MDB file on disk. This is the one object that is automatically appended to its collection upon creation.
Querydef | Creates a new DAO querydef object underlying the MFC querydef object. The object is not saved in the database until you call CDaoQueryDef::Append.
Recordset | No Create member function. Construct a recordset object (usually of a class derived from CDaoRecordset using the MFC wizards) and call its Open member function to run the query or open the table. This also creates a new DAO recordset object underlying the MFC recordset object.
Tabledef | Creates a new table in the specified database, and a DAO tabledef object to represent it. You must then add fields and possibly indexes to complete the table. The table is actually added to the database when you call CDaoTableDef::Append.
Workspace | Creates a new DAO workspace object underlying the MFC workspace object. The object is not appended to the Workspaces collection until you call CDaoWorkspace::Append.

See Also CDaoWorkspace::Open, CDaoWorkspace::Close, CDaoDatabase::Open, CDaoDatabase::Close, CDaoTableDef::Open, CDaoTableDef::Close, CDaoQueryDef::Open, CDaoQueryDef::Close, CDaoRecordset::Open, CDaoRecordset::Close, CDaoDatabase::Create, CDaoQueryDef::Create, CDaoTableDef::Create, CDaoWorkspace::Create


DAO: Opening DAO Objects

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Opening a DAO object implies that there is an existing object to be placed in an open state. This is distinct from creating a new object. In the typical case, the object to open is an element of the appropriate DAO collection, housed in some other DAO object.

An Open call puts the object into an open state, ready to be used. After using an object, you should explicitly close it.

Topics include:

  • Open member functions

  • Meaning of the Open action for different DAO objects

Open Member Functions

The following MFC DAO objects have Open member functions:

  • CDaoDatabase::Open

  • CDaoRecordset::Open

  • CDaoQueryDef::Open

  • CDaoTableDef::Open

  • CDaoWorkspace::Open

Meaning of the Open Action for Different DAO Objects

The concept of "open" has somewhat different meanings for different MFC DAO objects, as shown in the table “Meaning of Open for DAO Objects,” below. Typically, the object is already an element of a DAO collection that belongs to some other object. For example, each database object has a TableDefs collection that contains all tabledef objects in the database. The one object for which Open has a radically different meaning is CDaoDatabase; opening the object appends it to the Databases collection of a workspace object.

Meaning of Open for DAO Objects

Object | Meaning
Database | Opens an existing database ? usually a Microsoft Jet (.MDB) database.
Querydef | Opens the specified existing querydef object in the QueryDefs collection of a database.
Recordset | Runs the query defined by the recordset's SQL statement or by an associated querydef; or opens the specified tabledef via a table-type recordset.
Tabledef | Opens the specified existing tabledef object in the TableDefs collection of a database.
Workspace | Opens the default workspace unless you give the name of a workspace previously created with CDaoWorkspace::Create.

See Also CDaoWorkspace::Open, CDaoWorkspace::Close, CDaoDatabase::Open, CDaoDatabase::Close, CDaoTableDef::Open, CDaoTableDef::Close, CDaoQueryDef::Open, CDaoQueryDef::Close, CDaoRecordset::Open, CDaoRecordset::Close, CDaoDatabase::Create, CDaoQueryDef::Create, CDaoTableDef::Create, CDaoWorkspace::Create


DAO: Closing DAO Objects

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

All MFC DAO objects have Close member functions. Calling Close typically closes any subordinate objects, such as the active recordsets in a database object, before closing the parent object. The following illustrates closing a database object:

// pdbAccounts is an open CDaoDatabase object
pdbAccounts->Close( );

Note It is considered good practice to explicitly close your objects rather than relying on containing objects to close them.

Meaning of the Close Action for Different DAO Objects

The concept of “close” is similar for MFC DAO objects. Closing an object:

  • Releases memory associated with the object, including buffers used to store recordset data.

  • Releases the underlying DAO object.

  • Does not remove the object from any collection it belongs to. The exceptions are the workspace and recordset objects, which don’t persist between database engine sessions.

What Happens When You Close Objects

For details about what happens when you close an MFC DAO object, see the Close member function for that object's class:

  • CDaoDatabase::Close

  • CDaoQueryDef::Close

  • CDaoRecordset::Close

  • CDaoTableDef::Close

  • CDaoWorkspace::Close

Calling Close does not destroy the MFC object; you must do that separately.

Tip It is considered good programming practice to explicitly close your objects before they go out of scope.

See Also CDaoWorkspace::Open, CDaoWorkspace::Close, CDaoDatabase::Open, CDaoDatabase::Close, CDaoTableDef::Open, CDaoTableDef::Close, CDaoQueryDef::Open, CDaoQueryDef::Close, CDaoRecordset::Open, CDaoRecordset::Close, CDaoDatabase::Create, CDaoQueryDef::Create, CDaoTableDef::Create, CDaoWorkspace::Create


DAO: Accessing Implicit MFC DAO Objects

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes how to access the implicit MFC DAO objects that MFC creates for you in certain situations. The classic example is the workspace object associated with an existing CDaoDatabase or CDaoRecordset object. Normally you don't need an explicit CDaoWorkspace object, so you let MFC implicitly provide one. For a discussion, see the article DAO Database: Using Workspaces and Databases.

The Most Likely Case

In the most likely case — that you already have a CDaoDatabase or a CDaoRecordset object associated with the workspace you want to access — you can use data members of these objects to obtain a pointer to the implicit CDaoWorkspace object that they belong to. There are two scenarios, based on whether you are working from:

  • A database object (Scenario 1)

  • A recordset object (Scenario 2)

Scenario 1. A Database Object: One Level of Indirection

You have a CDaoDatabase object based on the workspace. Access the CDaoDatabase object's m_pWorkspace data member to obtain a CDaoWorkspace pointer, like this:

// pdbAccounts is a pointer to a CDaoDatabase object
// for the Accounts database
CDaoWorkspace* pws = pdbAccounts->m_pWorkspace;

Or you might simply use the implicit workspace to call a CDaoWorkspace member function:

pdbAccounts->m_pWorkspace->BeginTrans( );

Calling transaction functions in this way is common.

Scenario 2. A Recordset Object: Two Levels of Indirection

You have a CDaoRecordset object indirectly based on the workspace (through a CDaoDatabase). Follow these steps:

  1. Access the CDaoRecordset object's m_pDatabase data member to obtain a CDaoDatabase pointer.

  2. Access the database object's m_pWorkspace data member to obtain a CDaoWorkspace pointer, like this:
    // rsDelinquentAccts is an existing CDaoRecordset
// object based on the Accounts database
CDaoDatabase* pdbAccounts = rs.m_pDatabase;
CDaoWorkspace* pws = pdbAccounts->m_pWorkspace;

Or you might simply use the implicit workspace behind your recordset's implicit database to call a CDaoWorkspace member function:

pdbAccounts->m_pWorkspace->CommitTrans( );

Note This is the recommended method for accessing such functions because it doesn’t create a copy of a pointer to an implicit object. Copies of such pointers can be dangerous.

Uses for the Workspace Pointer

You can use the workspace pointer obtained in this indirect way to access the Workspaces collection, the Databases collection, properties of the database engine, and so on. Note that in most cases the workspace accessed this way is DAO's default workspace.

Caution If you store a copy to one of these pointers, be careful not to use it after the original object goes out of scope or is otherwise destroyed.

See Also DAO: Where Is..., DAO: Creating, Opening, and Closing DAO Objects


DAO: Using DAO in DLLs

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article provides some guidelines for using DAO in regular DLLs. In general, you should avoid performing any DAO construction, destruction, or operations inside the DLL's InitInstance or ExitInstance functions.

This article discusses:

  • Calling the AfxDaoTerm function

  • Destroying MFC DAO objects

Calling the AfxDaoTerm Function

The AfxDaoTerm function terminates the DAO database engine. In applications, AfxDaoTerm is called automatically, but in DLLs, you must explicitly invoke it before the DLL's ExitInstance function.

Some general guidelines you should follow include:

  • Create any MFC DAO objects after the DLL's InitInstance function.

  • Destroy these objects before calling AfxDaoTerm.

  • Call AfxDaoTerm before the DLL's ExitInstance function.

Because the AfxDaoTerm function terminates the database engine, you must call it after all MFC DAO objects have been destroyed.

Destroying MFC DAO Objects

All MFC DAO objects in the DLL must be destroyed before the call to AfxDaoTerm. This means you have to be careful about the scope of local and global DAO objects. For example, the following code will assert:

SomeExportedFunc( .. )
{
    CDaoDatabase db;
    db.Open( .. );

    // do something

    db.Close( );
    AfxDaoTerm( );
}

Because the DAO object db is a local variable, it remains in scope until SomeExportedFunc returns. Therefore, the call to AfxDaoTerm causes an assertion because DAO terminates while db still has scope. Similarly, a global DAO object will have scope throughout the life of the DLL, so a call to AfxDaoTerm will also result in an assertion.

To ensure that your MFC DAO objects are destroyed before calling AfxDaoTerm, avoid global objects and create local objects dynamically using the new operator:

SomeExportedFunc( .. )
{
    CDaoDatabase* pDB = new CDaoDatabase;
    pDB->Open( .. );

    // do something

    pDB->Close( );

    // destroy the object with delete
    delete pDB;

    // can now safely terminate DAO
    AfxDaoTerm( );
}

For related information, see Technical Note 54.

See Also DAO: Where Is...


DAO: General Performance Tips

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article offers tips for improving the performance of your MFC DAO applications. Use these tips as your starting point, and benchmark your changes. Keep in mind that these tips will often help, but there are no absolutes. Weigh everything in the context of your database and your application. Topics covered include:

  • Best tip

  • Recordset types

  • Selecting records

  • ODBC

  • Caching and double buffering

  • Opening databases

  • Attached tables

  • SQL

  • Transactions

  • Locating records

  • Other tips

How you improve performance in a database application depends on what kind of performance improvement you need. You might need some of the following kinds of performance improvements more than others:

  • Better query speed

  • Faster record location

  • Faster scrolling through records

  • Up-to-date record content in multi-user environments

  • Better performance with external databases, especially ODBC data sources

Best Tip

The design of your data is usually a bigger factor in performance than the design of your code:

  • Use Microsoft Access to examine your database design, queries, and indexes. Run your queries in Access and use the results to adjust your table and index designs for better performance. Then save the queries in your database for use from your code.

  • Normalize your database schema to avoid storing multiple copies of your data. Consult any standard database text, such as C.J. Date's Introduction to Database Systems, 10th edition (Addison-Wesley, 1995), or consult the Microsoft Access documentation.

Also:

  • Store infrequently updated tables in your local Microsoft Jet (.MDB) database. If the data doesn’t change often, you can keep a local copy for queries and avoid having to move the data across the network.

Recordset Types

  • In general, use a table-type recordset rather than either a dynaset-type recordset or a snapshot-type recordset if possible.

  • For remote data, use snapshot-type recordsets rather than dynaset-type recordsets. But beware of Memo fields, especially in ODBC data sources. If the data contains Memo fields, use a dynaset-type recordset instead if you won’t be retrieving all the fields from all the rows. Dynaset-type recordsets are also better for COM objects in ODBC data sources.

  • For ODBC data with COM objects or Memo fields, use dynaset-type recordsets instead of snapshot-type recordsets.

Selecting Records

  • For dynaset-type recordsets and snapshot-type recordsets, select only the fields you need instead of all fields.

  • For snapshot-type recordsets against ODBC data sources, use the dbForwardOnly option in your recordsets if you’ll be making a single pass through your data.

  • For dynaset-type recordsets against ODBC data sources, cache multiple records. See the article DAO Recordset: Caching Multiple Records for Performance.

  • If you're adding records to a dynaset-type recordset, especially against an ODBC data source, use the dbAppendOnly option.

  • Requery recordsets rather than reopening them. Note that you lose this advantage if you change filters or sorts before you requery.

  • Parameterize queries instead of using dynamic SQL statements, especially against ODBC data sources.

  • Store queries instead of using dynamic SQL statements, especially on machines with low memory.

  • Refresh current field values by calling Move with a parameter of AFX_MOVE_REFRESH instead of calling MoveNext and MovePrev. (Calling Move with a parameter of 0 is equivalent.)

ODBC

  • Attach ODBC tables to a local Microsoft Jet (.MDB) database rather than opening the ODBC data source directly.

  • Reduce your ODBC timeouts for faster performance in failure cases.

  • For ODBC data with COM objects or Memo fields, use dynaset-type recordsets instead of snapshot-type recordsets.

  • For snapshot-type recordsets against ODBC data sources, use the dbForwardOnly option in your recordsets.

  • For dynaset-type recordsets against ODBC data sources, cache multiple records. See the article DAO Recordset: Caching Multiple Records for Performance.

  • With ODBC SQL statements that don’t retrieve data, use pass-through queries where possible. For related information, see the article DAO Querydef: Action Queries and SQL Pass-Through Queries.

  • Speed ODBC finds by downloading to a local indexed table and seeking. If you will be making numerous finds in the data, copy it to a local Microsoft Jet database table and use Seek to locate information.

  • On ODBC data, use Find only on indexed fields; otherwise, open a new recordset using an SQL statement with an appropriate WHERE clause.

For more information about working with ODBC data sources, see the articles Database Topics (DAO) and DAO External: Working with External Data Sources.

Caching and Double Buffering

  • For best performance, turn off MFC's double-buffering mechanism. However, the tradeoff is that you must write more code to update a field. For more information, see the article DAO Record Field Exchange: Double Buffering Records.

  • Cache multiple records when you are using an ODBC data source. See the article DAO Recordset: Caching Multiple Records for Performance.

  • Cache tabledef references if they will be used many times. Keep your CDaoQueryDef objects open and reuse them rather than recreating them.

Opening Databases

  • Open databases for exclusive use if you are the only user. Open databases as read-only if all users will be read-only.

  • Use the dbDenyWrite option if nobody else will be writing to the database.

  • Retrieve data from ODBC databases by attaching to a Microsoft Jet (.MDB) database instead of opening the ODBC database directly.

Attached Tables

  • Attach ODBC tables to a local Microsoft Jet (.MDB) database rather than opening the ODBC data source directly.

  • Open attached Microsoft Jet tables as table-type recordsets by parsing the tabledef connect string for the database name and then opening that database directly.

SQL

  • With ODBC SQL statements that don’t retrieve data, use pass-through queries where possible. For related information, see the article DAO Querydef: Action Queries and SQL Pass-Through Queries.

  • Replace code loops that run a query again and again with the equivalent SQL statements to run the query once for the whole loop. For example, rather than doing 100 update calls, run one bulk query for all of the affected records.

  • Replace repeated execution of the same dynamic SQL with a temporary query. (This applies only if you are using a querydef pointer in CDaoRecordset::Open to create your recordset.)

Transactions

  • Always embed your MFC DAO code in transactions if you are performing multiple updates. Balance transaction sizes against the likely available memory. Don’t try to do ten thousand large updates in a single transaction. Instead, break the work into smaller lots of, say, 500 records.

Locating Records

  • Use Seek rather than Find. (Seek only works with table-type recordsets.)

  • Return to a location in a recordset using bookmarks rather than Find. See the article DAO Recordset: Bookmarks and Record Positions.

  • Speed ODBC finds by downloading to a local indexed table and seeking. If you will be making numerous finds in the data, copy it to a local Microsoft Jet database table and use Seek to locate information.

  • On ODBC data, use Find only on indexed fields; otherwise, open a new recordset.

Other Tips

  • Use the power of Microsoft Jet queries to save writing and debugging code. For example, the Microsoft Jet database engine allows you to update the results of join queries and automatically distributes the changes to the underlying tables.

  • Replace short Memo fields with long text fields.

  • Replace floating-point numbers with integers.


DAO Collections

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to access the “collections” in which DAO keeps active DAO objects at all levels of the DAO object hierarchy. The article also explains how the collections are exposed in MFC. Topics covered include:

  • DAO collections: definitions

  • How MFC exposes DAO collections

  • The default object in a collection

  • How to access a collection

  • The information you obtain about objects in a collection

  • Contents of MFC DAO information structures

  • Primary, Secondary, and All information

  • Information about collections in DAO

DAO Collections: Definition

In DAO, each object in the object hierarchy maintains one or more "collections" of subordinate objects. For example, the Microsoft Jet database engine maintains a collection of open workspaces. Each workspace object maintains a collection of open databases (and other collections, related to security). And so on. For a list of the DAO objects and the collections they house, see the topic "Data Access Objects and Collections Reference" in DAO Help.

How MFC Exposes DAO Collections

In the MFC DAO classes, MFC doesn't maintain a collection (such as a CObArray) of C++ objects parallel to the underlying DAO collection. Rather, MFC supplies member functions and/or data members through which you can access the underlying collection itself in DAO, where the DAO collections are stored. For example, class CDaoWorkspace supplies the GetWorkspaceCount member function to determine how many workspaces are in the database engine's Workspaces collection and the GetWorkspaceInfo member function to examine information about any workspace in the collection.

In general, the MFC DAO classes supply similar functions for all relevant DAO collections. The one significant exception is the Recordsets collection of the database object. MFC does not supply GetRecordsetCount and GetRecordsetInfo member functions in class CDaoDatabase. When you work with recordsets, you always have an explicit MFC CDaoRecordset object in your application. It's up to you to keep track of which recordsets you have open.

The Default Object in a Collection

The first element in a DAO collection, at element 0, is the default element of the collection. In particular, DAO's default workspace is element 0 in the Workspaces collection. Collections are zero-based.

How to Access a Collection

The following procedure uses the TableDefs collection of a CDaoDatabase object to illustrate the general process for accessing objects in a DAO collection.

To access the TableDefs collection (for example)

  1. Construct a CDaoDatabase object, or get a pointer to one from a CDaoRecordset object.

  2. Call the object's Open member function unless you have obtained a database pointer from a recordset.

  3. Use the GetTableDefCount and GetTableDefInfo member functions of the object to determine how many tabledefs the collection contains and to loop through the collection, obtaining information about each tabledef object.

For an example, see the LISTVIEW.CPP file in the MFC Database sample DAOVIEW. For a procedure, see the article DAO Collections: Obtaining Information About DAO Objects.

The Information You Obtain About Objects in a Collection

To obtain information about the objects in a collection, you call a GetXInfo member function of the appropriate class. This function returns an object of one of the CDaoXInfo structures listed in the table Classes for Obtaining Information About DAO Objects in the article DAO Collections: Obtaining Information About DAO Objects. In general, there is a CDaoXInfo structure associated with each DAO object. These structures are commonly referred to as the MFC DAO “information structures.”

Contents of MFC DAO Information Structures

A typical information structure looks something like this:

struct CDaoDatabaseInfo
{
   CString m_strName;       // Primary
   BOOL m_bUpdatable;       // Primary
   BOOL m_bTransactions;    // Primary
   CString m_strVersion;    // Secondary
   long m_lCollatingOrder;  // Secondary
   short m_nQueryTimeout;   // Secondary
   CString m_strConnect;    // All
};

For detailed descriptions of the structure members, see the individual structure in the Class Library Reference. Structures are listed in the table Classes for Obtaining Information About DAO Objects in the article DAO Collections: Obtaining Information About DAO Objects.

Primary, Secondary, and All Information

The notations “Primary,” “Secondary,” and “All” indicate which MFC DAO structure members are filled when you call a function such as GetDatabaseInfo. You can specify that you want just primary information, both primary and secondary information, or all information. Some structures don’t include anything under the All designation.

Caution Using the Secondary and All options can be slow. In general, Primary is faster than Secondary, and Secondary is faster than All. Don’t use All unless you must.

For more information about using GetTableDefCount, GetTableDefInfo, and similar functions, see the article DAO Collections: Obtaining Information About DAO Objects.

Information About Collections in DAO

For general information about the DAO collections, see the topic "Data Access Objects and Collections Reference" in DAO Help.

See Also DAO: Where Is...


DAO Collections: Obtaining Information About DAO Objects

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Objects of most of the MFC DAO classes contain “collections” of subordinate objects. For example, a CDaoDatabase object contains collections of tabledefs, querydefs, and relations. For an explanation of how these collections fit into the MFC implementation, see the article DAO Collections.

The present article explains how to obtain information about the objects in a collection. The example given uses the database object’s QueryDefs collection, but the same mechanism applies to other collections throughout the MFC implementation of DAO.

Topics covered include:

  • Functions for accessing DAO collections

  • Information returned by the GetXInfo functions

  • Example: Obtaining Information About Querydefs

  • Constants for specifying the levels of information you want

Functions for Accessing DAO Collections

Access the objects in a DAO collection through the GetXCount and GetXInfo member functions of the appropriate class, where X stands for Database, Field, Index, Parameter, Query, Table, Relation, or Workspace. The following table lists the available collection-access functions for each MFC class.

Class Member Functions for Accessing Collections

Class | Count objects in collection | Get information about a specified object
CDaoWorkspace | GetDatabaseCount, GetWorkspaceCount | GetDatabaseInfo, GetWorkspaceInfo
CDaoDatabase | GetTableDefCount, GetRelationCount, GetQueryDefCount | GetTableDefInfo, GetRelationInfo, GetQueryDefInfo
CDaoTableDef | GetFieldCount, GetIndexCount | GetFieldInfo, GetIndexInfo
CDaoQueryDef | GetFieldCount, GetParameterCount | GetFieldInfo, GetParameterInfo
CDaoRecordset | GetFieldCount, GetIndexCount | GetFieldInfo, GetIndexInfo

Information Returned by the GetXInfo Functions

In general, use GetXCount functions to determine the upper bound for looping through a collection. On each iteration of the loop, call GetXInfo functions to retrieve the information. The GetXInfo functions return a reference to an object of class CDaoXInfo, which you can examine. Each different CDaoXInfo class (technically a C++ structure) supplies different information. You pass an object of type CDaoXInfo in the second (xinfo) parameter.

Note DAO collections are zero-based. When you iterate a collection, begin with element 0.

The following table lists the CDaoXInfo classes. See the class for details about its members.


DAO Database

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the role of CDaoDatabase objects in your application. For task-oriented information about using database objects, see the article DAO Database: Using Workspaces and Databases. For an understanding of the DAO database object underlying each MFC CDaoDatabase object, see the following topics in DAO Help:

  • Database Object

  • Databases Collection

Topics covered in this article include:

  • Database: Definition

  • External databases

  • Database collections

  • Database roles

  • Accessing database objects

  • Database persistence

  • Further reading about databases

Database: Definition

A DAO database object, represented in MFC by class CDaoDatabase, represents a connection to a database through which you can operate on the data. You can have one or more CDaoDatabase objects active at a time in a given workspace, represented by a CDaoWorkspace object.

For information about database management systems (DBMSs) you can work with, see What Data Sources Can I Access with DAO and ODBC?.

External Databases

Besides using CDaoDatabase to work with Microsoft Jet (.MDB) databases, you can also access external data sources, particularly Open Database Connectivity (ODBC) data sources. For a list of external data sources, see the topic External Data Source: Definition in the article DAO: Working with External Data Sources.

Database Collections

In DAO:

  • Each workspace object contains a collection of open database objects, called the Databases collection.

  • Each DAO database objects contains collections of tabledefs, querydefs, recordsets, and relations.

In MFC, access to a workspace’s Databases collection is through member functions of class CDaoWorkspace. Access to a database object’s collections is through member functions of class CDaoDatabase.

Note DAO collections are not collections in the sense of the MFC collection classes. They are an integral part of DAO.

Note MFC exposes all of a database’s collections via member functions except for the Recordsets collection. In MFC, you always have an explicit CDaoRecordset object for each recordset you create, and it is up to you to track these objects.

For more information about DAO collections in MFC, see the article DAO Collections. For related information, see the topic "Databases Collection" in DAO Help.

Database Roles

CDaoDatabase allows you to:

  • Create new Microsoft Jet (.MDB) database files.

  • Store tabledef objects that you can use to manipulate the structure of the database’s tables.

  • Store querydef objects so you can reuse the queries they represent later.

  • View and manipulate data in the database’s tables.

  • Work with data in local or remote databases.

  • Work with the database’s collections.

Accessing Database Objects

When you open a CDaoRecordset object without specifying an open CDaoDatabase object, MFC implicitly creates a CDaoDatabase object, along with the CDaoWorkspace that contains the database and the underlying DAO database object. You can also create explicit CDaoDatabase objects.

See the article DAO: Accessing Implicit MFC DAO Objects for information on accessing:

  • The CDaoDatabase object associated with a CDaoRecordset object.

  • The CDaoWorkspace object associated with a CDaoDatabase object.

Database Persistence

Database objects exist in memory for the life of a database engine session. When that session terminates, the default workspace, the Workspaces collection, the Databases collection in each open workspace, and the database objects in the Databases collection(s) cease to exist (although the databases they represent do persist). These software objects are not stored on disk or in a database. When you begin a new database engine session and want to use the workspaces and databases you used in the last session, you must re-create any explicit workspace objects you need, and reopen any databases you were using in the workspace.

Tip Use a Windows registry entry to preserve a record of the workspaces and databases you had open during a database engine session.

Further Reading About Databases

For more information about databases in MFC, see the following articles (in recommended reading order):

  • DAO Database: Using Workspaces and Databases

  • DAO External: Working with External Data Sources

  • DAO: Accessing Implicit MFC DAO Objects

  • DAO Collections

  • DAO Tabledef

  • DAO Querydef

  • DAO Recordset

See Also DAO: Where Is..., DAO: Database Tasks


DAO Database: Using Workspaces and Databases

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to use CDaoWorkspace and CDaoDatabase objects. Topics covered include:

  • A typical workspace scenario

  • Transactions in the typical scenario

  • Beyond the typical scenario

A Typical Workspace Scenario

In the majority of data access applications, you work less at the workspace level than at the database or even recordset level. It might seem the normal thing to construct an explicit CDaoWorkspace object, then from it construct a CDaoDatabase object and from that construct CDaoRecordset, CDaoQueryDef, and CDaoTableDef objects. But the more typical approach is one of the following:

  • Construct a CDaoDatabase object, perhaps stored in your CDocument-derived class. Then from it construct the necessary recordsets and other objects. You're likely to do this if you want to maintain a connection to a single database for the life of your application, or at least the life of your document. For related information, see the articles MFC: Using Database Classes with Documents and Views, MFC: Using Database Classes Without Documents and Views, and DAO: Writing a Database Application.

  • Construct recordsets as needed, relying on MFC to create the necessary CDaoDatabase and CDaoWorkspace objects behind the scenes. You're likely to do this if you prefer to construct recordsets within the scope of a function, for example to run a query based on a menu command.

    Note This is inefficient if you are continually opening and closing the same database. In that case, create an explicit CDaoDatabase object and use it for the life of your application.

Transactions in the Typical Scenario

The primary action taken on a workspace object that might be called typical is to use the object for transactions against one or more databases. The transaction commands in MFC are members of class CDaoWorkspace.

To access transaction commands in the most typical case, you can use the implicit workspace that MFC creates behind CDaoDatabase and CDaoRecordset objects (one implicit workspace for multiple objects). To issue transaction commands, such as BeginTrans, CommitTrans, or Rollback, you can choose to call those member functions of CDaoWorkspace through the pointer stored in your CDaoRecordset or CDaoDatabase object. For details about accessing such pointers, see the article DAO: Accessing Implicit MFC DAO Objects.

For example, from a recordset object, you might call:

// prs is a pointer to an already opened
// CDaoRecordset object
prs->m_pDatabase->m_pWorkspace->BeginTrans( );
...

Beyond the Typical Scenario

The typical scenario is not enough in some fairly rare cases. For a discussion of when you might need an explicit CDaoWorkspace object, see the article DAO Workspace.

See Also DAO: Where Is..., DAO Workspace: Managing Transactions, DAO Workspace, DAO Database, DAO: Creating, Opening, and Closing DAO Objects


DAO Workspace

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the role of CDaoWorkspace objects in your application. For task-oriented information about using workspaces, see the article DAO Database: Using Workspaces and Databases. For an understanding of the DAO workspace object underlying each MFC CDaoWorkspace object, see the topic "Workspace Object" in DAO Help.

Topics covered include:

  • Workspace: definition

  • MFC workspaces are transaction spaces

  • Database engine access

  • Workspace collections

  • Default workspace

  • Workspace roles

  • Accessing workspace objects

  • Workspace persistence

  • Further reading about workspaces

Workspace: Definition

A DAO workspace, represented in MFC by class CDaoWorkspace, manages a session with the Microsoft Jet database engine. A workspace can contain one or more open DAO database objects, represented in your program, explicitly or implicitly, by CDaoDatabase objects. In DAO, workspaces manage a single transaction space in which any transaction applies to all open databases and recordsets. DAO workspaces also manage database security.

Transaction Spaces

In MFC, workspaces are primarily transaction spaces; MFC does not expose DAO's security features, although you can program them yourself by directly calling DAO. For more information, see Technical Note 54.

Database Engine Access

In DAO, a separate DBEngine object manages the properties of the single instance of the Microsoft Jet database engine underlying multiple open workspaces. In MFC, access to the database engine's properties is through static member functions of class CDaoWorkspace. For more information, see the article DAO Workspace: The Database Engine.

Workspace Collections

In DAO:

  • The DBEngine object contains a "collection" of open workspace objects, called the Workspaces collection.

  • Each DAO workspace object in turn contains collections of open databases, active users, and active user groups.

In MFC, access to both the DBEngine's Workspaces collection and any workspace's Databases collection is through member functions of a CDaoWorkspace object. MFC doesn’t provides direct access to the Users collection or the Groups collection, which are part of DAO's security support; and MFC doesn’t expose DAO security features. For information about DAO collections in MFC, see the article DAO Collections.

Default Workspace

In DAO, the first workspace in the Workspaces collection is called the default workspace. By default, if you open databases, they exist within the default workspace. In MFC, if you open a database object without specifying a workspace, or open a recordset object without specifying a database object, MFC implicitly uses DAO's underlying default workspace to manage transactions.

You seldom have to explicitly create a CDaoWorkspace object, but you can create explicit CDaoWorkspace objects if you need an explicit object for any of the activities described in Workspace Roles.

Information About Workspaces in DAO Help

For information about workspaces in DAO, see the topic "Workspace Object" in DAO Help. For more information about workspaces in MFC, see the rest of this article and the article DAO Database: Using Workspaces and Databases.

Workspace Roles

CDaoWorkspace provides the following:

  • Explicit access to DAO's default workspace.

  • Access to the Workspaces collection or the default workspace's Databases collection.

  • A separate transaction space if you need to separate the transactions on one database from those on another database.

  • Access to the properties of the database engine.

Accessing Workspace Objects

MFC implicitly creates a CDaoWorkspace object, and its underlying DAO workspace, when you:

  • Construct a CDaoDatabase object without specifying the workspace.

  • Construct a CDaoRecordset object without specifying the database.

See the article DAO: Accessing Implicit MFC DAO Objects for information on accessing:

  • The CDaoWorkspace object associated with a CDaoDatabase object

  • The CDaoWorkspace object associated with the CDaoDatabase object associated with a CDaoRecordset object

Workspace Persistence

Workspaces exist in memory for the life of a database engine session. When that session terminates, the default workspace, the Workspaces collection, and the Databases collections of any workspaces cease to exist (the actual databases do persist). These software objects are not stored on disk or in a database. When you begin a new database engine session and want to use the workspaces and databases you used in the last session, you must re-create any explicit workspace objects you need and reopen any databases you want associated with a workspace.

Tip Use a Windows registry entry to preserve a record of the workspaces and databases you had open during a database engine session.

Further Reading About Workspaces

For more information about workspaces in MFC see the following articles (in the recommended order):

  • DAO Database: Using Workspaces and Databases

  • DAO Workspace: Explicitly Opening the Default Workspace

  • DAO: Accessing Implicit MFC DAO Objects

  • DAO Workspace: Opening a Separate Transaction Space

  • DAO Workspace: Accessing Properties of the Database Engine

  • DAO Collections

See Also DAO: Where Is..., DAO Database: Using Workspaces and Databases, DAO Workspace: The Database Engine, DAO Database, DAO: Creating, Opening, and Closing DAO Objects


DAO Workspace: Explicitly Opening the Default Workspace

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Normally you don't need to refer explicitly to DAO's default workspace. MFC uses it automatically when you open new databases, recordsets, tabledefs, and querydefs. But sometimes you need explicit access to the default workspace — for example, to access the Workspaces collection or to set database engine properties. For that kind of access, you might need a CDaoWorkspace object.

The Most Likely Case

The most likely case is that you already have a CDaoDatabase object or a CDaoRecordset object based on the default workspace (or on an additional workspace). For those cases, see the article DAO: Accessing Implicit MFC DAO Objects. Otherwise, if you don't have a database or recordset object handy, you can still open the default workspace as follows:

To explicitly open the default workspace

  1. Construct a CDaoWorkspace object.

  2. Call the object's Open member function. Specify NULL for the lpszName parameter.

  3. Call other member functions or access data members.

Closing this CDaoWorkspace object has no effect on DAO's default workspace. That workspace is terminated when the database engine session terminates. For information on database engine termination, see the article DAO Workspace: The Database Engine.

See Also DAO: Where Is..., DAO: Accessing Implicit MFC DAO Objects, DAO Workspace, DAO: Creating, Opening, and Closing DAO Objects


DAO Workspace: Managing Transactions

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the MFC facilities available for managing transactions and refers you to additional information in DAO Help. For general transaction information in DAO, see the topic "BeginTrans, CommitTrans, Rollback Methods" in DAO Help.

Topics covered include:

  • Transaction: defined

  • Transaction spaces

  • Transaction example

  • Additional reading about transactions

Transaction: Defined

A transaction is a series of changes made to a database's data and/or schema. Mark the beginning of a transaction by calling the BeginTrans member function of class CDaoWorkspace. Commit the transaction using the CommitTrans member function, or undo all your changes since BeginTrans using the Rollback member function.

The key idea of transactions is that the operation is “atomic” — a group of related smaller operations must all succeed for the whole operation to succeed. If one small operation fails, the whole operation fails.

There is an implicit transaction while action queries are running. If a query doesn't complete for any reason, it is automatically rolled back. Transactions are optional and can be nested up to five levels. (This is in contrast to ODBC, which does not permit nested transactions.) Transactions increase the speed of data changing operations and enable changes to be reversed easily.

The current transaction consists of all changes made to a recordset object after you last called the BeginTrans member function and before you call the Rollback or CommitTrans member functions.

Transaction Spaces

The workspace object defines a transaction space. Transactions are global to the workspace in which they occur. They affect all open databases, recordsets, and querydefs in the same workspace. If you have several open recordsets and/or databases in a workspace, each call to BeginTrans, CommitTrans, and Rollback applies to all of the objects.

For example, suppose you have called BeginTrans for a workspace and you begin updates through two recordsets that belong to database objects in the same workspace. If you call CommitTrans or RollBack in the workspace, the call affects both recordsets, even if they are open on different databases.

If this transaction model is not what you need, you can open separate transaction spaces by opening separate workspaces. Create a new CDaoWorkspace object for each separate transaction space. For more information, see the article DAO Workspace: Opening a Separate Transaction Space.

Transaction Example

The following example illustrates transactions by using two recordsets to delete a student's enrollment from a school registration database. First it removes the student from all classes in which the student is enrolled. Then it removes the student's master record, after which the student no longer exists in the database.

The Delete calls in both recordsets must succeed, so a transaction is required.

Important The example shown illustrates correct transaction procedure, but for the illustrated case this is not the most efficient way to do the job. For details, see the discussion in Efficiency Considerations for This Example.

The example assumes the existence of:

  • m_dbStudentReg, a document data member that contains a CDaoDatabase object already open on the database.

  • m_rsStudentSet, a document data member that contains a recordset object based on class CStudentSet, derived from CDaoRecordset. This recordset returns all enrolled students.

  • CEnrollmentSet, a second CDaoRecordset-derived class. This recordset, as written by ClassWizard, returns all students enrolled in all classes. The example code filters the recordset to return only the records representing classes in which the specified student is enrolled.

The example modifies the default SQL string defined with ClassWizard before opening the recordset. The modification filters the records with a student ID passed in as a parameter.

BOOL CEnrollDoc::RemoveStudent(CString strStudentID)
{
    // Construct a recordset for courses student is in
    CEnrollmentSet rsEnrollmentSet( &m_dbStudentReg );

    // Define the SQL string for the recordset to
    // Filter records with the SQL keyword WHERE
    CString strSQL = rsEnrollmentSet.GetDefautlSQL( ) +
                "WHERE [Student ID] = " + strStudentID;
    try
    {
        // Open the recordset using
        // the modified SQL string
        rsEnrollmentSet.Open( dbOpenDynaset, strSQL );

        // Start the transaction
        m_dbStudentReg.m_pWorkspace->BeginTrans( );

        // Remove the student from all classes the
        // student is enrolled in
        while ( !rsEnrollmentSet.IsEOF( ) )
        {
            rsEnrollmentSet.Delete( );
            rsEnrollmentSet.MoveNext( );
        }
        // Delete the student's master record
        m_rsStudentSet.Delete( );

       // Commit the transaction
       m_dbStudentReg.m_pWorkspace->CommitTrans( );
    }
    catch(CDaoException* e)
    {
        m_dbStudentReg.m_pWorkspace->Rollback( );
        AfxMessageBox( "Failed to remove student." );
        e->Delete( );
        return FALSE;
    }
    m_rsStudentSet.Close( );
}

For information about the try/catch exception handling shown here, see the article Exceptions: Database Exceptions and the CDaoException class.

Efficiency Considerations for This Example

The transaction example shown in Transaction Example shows you how to do transactions. But in some cases, as in deleting records, transactions may not be most efficient approach. In fact, there are two more efficient approaches to deleting the student record along with all related records for that student:

  • Use cascade deletes.

    If the student registration database defines a relation between the STUDENT and ENROLLMENT tables with the cascade delete attribute set, you can delete a single student record in the STUDENT table and let cascade deletes remove all related records in the ENROLLMENT table.

    For information about cascade deletes, see the topic "Relation Object" in DAO Help. Relations in MFC are discussed under class CDaoDatabase in the Class Library Reference.

  • Use a bulk query.

    A bulk query would delete all records in any tables you specify that contain the student ID for the student you want to delete.

    The query’s SQL statement looks like this:

    DELETE FROM STUDENT,ENROLLMENT WHERE STUDENT.StudentID = ENROLLMENT.StudentID AND StudentID = strStudentID

    The expression “STUDENT.StudentID = ENROLLMENT.StudentID” “joins” the tables on the StudentID field. The expression “StudentID = strStudentID” finds those records in the join that have the particular student ID in strStudentID. The SQL deletes those records.

Transactions do have a role to play, of course. The point is that you should use the best approach for the particular task.

Additional Reading About Transactions

For more information about transactions, see the following topics in DAO Help:

  • BeginTrans, CommitTrans, Rollback Methods

  • CreateWorkspace Method

  • BOF, EOF Properties

  • IsolateODBCTrans Property

In the Class Library Reference, see: CDaoWorkspace, especially the BeginTrans, CommitTrans, Rollback, and SetIsolateODBCTrans member functions.

Also see CDaoRecordset, especially the AddNew, Edit, Update, Delete, IsBOF, and IsEOF member functions.

See Also DAO: Where Is..., DAO Recordset


DAO Workspace: Opening a Separate Transaction Space

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

A workspace defines a single transaction space for all databases open within it. This means that if you begin a transaction in a workspace, then update several recordsets on several databases in the workspace, and then commit or roll back the transaction, the commitment or rollback applies to all of the databases.

Sometimes, however, you need to separate one set of transactions — applying to database A — from another set — applying to database B.

To open a separate transaction space

  1. Construct a new CDaoWorkspace object.

  2. Call the workspace object's Create member function. Specify a unique name in the lpszName parameter to make this workspace distinct from the default workspace or any other workspaces. Each workspace you create explicitly has a different name.

  3. Open one or more databases in the new workspace.

  4. Run transactions on the new workspace.

Transactions on the new workspace will be distinct from those on other workspaces. For related information about ODBC data sources, see the article DAO External: Working with External Data Sources and see CDaoWorkspace::SetIsolateODBCTrans.

For a general discussion of using transactions, see the article DAO Workspace: Managing Transactions. That article also leads you to topics in DAO Help.

See Also DAO: Where Is..., DAO Workspace: Managing Transactions, DAO: Creating, Opening, and Closing DAO Objects


DAO Workspace: The Database Engine

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

MFC and DAO use the Microsoft Jet database engine, currently version 3.0, to retrieve data from and store data in user and system databases. The Microsoft Jet database engine is the data manager component on which various implementations are built, such as the MFC DAO classes, Microsoft Access, and Microsoft Visual Basic, and the Microsoft Desktop Database Drivers (currently version 3.0).

This article explains how you interact with the database engine via MFC. Topics covered include:

  • Data sources you can access

  • How MFC exposes the database engine

  • Database engine collections

  • Initializing and uninitializing the database engine

Data Sources You Can Access

While the database engine is best suited for working with Microsoft Jet (.MDB) databases, you can access several ISAM databases and any database for which you have an ODBC driver, including remote databases such as Microsoft SQL Server or Oracle. For more information about these non-.MDB sources, see the article DAO External: Working with External Data Sources.

How MFC Exposes the Database Engine

In DAO, the database engine is represented by a DBEngine object. This object sits at the top of the DAO object hierarchy and contains all of the other objects, such as workspaces and databases. For detailed information about this DAO object, see the topic "DBEngine Object" in DAO Help. To view the DAO object hierarchy, see the topic "Data Access Object Hierarchy" in DAO Help.

In MFC, the DBEngine object is not exposed directly via an MFC class. Instead, all access to the underlying DAO database engine object is through a set of static member functions in class CDaoWorkspace. These member functions provide access to database engine properties that you can set or get to configure your database sessions. You can access the database engine through any workspace object, whether MFC creates the object implicitly or you create it explicitly. In the majority of situations, you will not need to set these properties. You can rely on the defaults instead.

Database Engine Collections

DAO's DBEngine object houses two important collections used with MFC:

  • Workspaces

  • Errors

The DBEngine’s Workspaces Collection

The Workspaces collection contains all open DAO workspace objects that you have explicitly appended to the collection. See the article DAO Collections: Obtaining Information About DAO Objects for a discussion of how to use the Workspaces collection.

The DBEngine’s Errors Collection

The Errors collection contains one DAO error object for each error returned by the most recent DAO operation. In most error situations, particularly when you are working with a Microsoft Jet (.MDB) database, the collection contains one object. If you are using an ODBC data source, it is likely that the collection might contain more than one error object. In MFC, all DAO errors are translated into thrown exceptions of type CDaoException. See class CDaoException and the article Exceptions: Database Exceptions for a discussion of how to work with MFC's DAO exceptions.

Initializing and Uninitializing the Database Engine

MFC loads a single instance of the DAO DBEngine object, housed in a DLL, per application. Thus your database engine sessions are limited to your application. Your workspaces are not available to other applications or users.

Initializing the Database Engine

MFC initializes the database engine, beginning your database engine session, the first time your application creates or opens a workspace, either implicitly or explicitly. For more information about explicit and implicit workspaces, see the article DAO Workspace.

Uninitializing the Database Engine

MFC uninitializes the database engine, ending your database engine session, when your application terminates.

See Also DAO: Where Is..., DAO Workspace, DAO Workspace: Accessing Properties of the Database Engine


DAO Workspace: Accessing Properties of the Database Engine

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

If you need to get or set any of the properties of the database engine behind your workspaces, you'll need a CDaoWorkspace object whose static member functions provide access to those properties.

To access properties of the database engine

  1. Construct a CDaoWorkspace object, or use a pointer to one provided by a CDaoRecordset or CDaoDatabase object.

  2. Call any of the workspace's static member functions. You do not need to call Open or Create to call these member functions.

Accessing Database Engine Properties

The following table describes the CDaoWorkspace member functions that relate to database engine properties.

Workspace Member Functions for Database Engine Access

DAO property | Member functions | Description
Version | GetVersion | Get the version number of the Microsoft Jet database file.
DefaultPassword | SetDefaultPassword | Specify the default password that the database engine uses when you create new workspaces without specifying a password. Setting this property is optional. You can instead require that new workspaces supply a password.
DefaultUser | SetDefaultUser | Specify the default user name that the database engine uses when you create new workspaces without specifying a user name. As with SetDefaultPassword, setting this property is optional.
LoginTimeout | GetLoginTimeout, SetLoginTimeout | Specify the number of seconds to wait before an ODBC connection attempt times out. DAO sets a default, so setting this property is optional.
IniPath | GetIniPath, SetIniPath | Specify a Windows registry key under which are stored application-specific options relating to special settings for the database engine. Setting this property is optional and not often needed.

CDaoWorkspace also supplies member functions for compacting (or copying) a Microsoft Jet (.MDB) database and for attempting to repair a corrupt .MDB database file. See CDaoWorkspace::CompactDatabase and CDaoWorkspace::RepairDatabase.

More Information About These Properties

For more information, see the DAO Help topics for the named properties in the table Workspace Member Functions for Database Engine Access above. Topic names are of the form: “propertyname Property.” For example, the topic for the Version property is Version Property. See also the CDaoWorkspace member functions listed and the article DAO Workspace: Accessing Properties of the Database Engine.

See Also DAO: Where Is..., DAO Workspace, DAO Workspace: The Database Engine


DAO External: Working with External Data Sources

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the best approaches to using the MFC DAO classes with external data sources, primarily ODBC data sources.

Topics include:

  • External data source: definition

  • External data sources you can use

  • External data access choices

  • Performance considerations with external data

  • When you might need to open an external table directly

  • Other articles about accessing external data

  • For more information about accessing external data

External Data Source: Definition

Aside from working with a Microsoft Jet (.MDB) database on your local machine, you can use the MFC DAO classes to access external data of several kinds. External data includes data located in:

  • An ODBC data source, either local or on a network server.

  • An ISAM database such as dBASE® or Microsoft FoxPro®, accessible through the Microsoft Jet database engine, either locally or on a network server.

  • A Microsoft Jet (.MDB) database, created directly with Microsoft Access or created with DAO and stored either locally or on a network server, that contains tables you want to attach to a primary Microsoft Jet database.

External Data Sources You Can Use

The discussion in this and related articles applies to the following external data sources:

  • Microsoft FoxPro®, versions 2.0, 2.5, and 2.6. Can import and export data to and from version 3.0 but can’t create objects.

  • dBASE III®, dBASE IV®, and dBASE 5.0®.

  • Paradox™, versions 3.x, 4.x, and 5.x.

  • Databases using the Microsoft Jet database engine (Microsoft Access, Microsoft Visual Basic, and Microsoft Visual C++), versions 1.x, 2.x, and 3.0.

  • ODBC data sources, including but not limited to Microsoft SQL Server, SYBASE® SQL Server, and ORACLE® Server. An ODBC data source is any DBMS for which you have the appropriate ODBC driver. For Visual C++ versions 2.0 and later, you need 32-bit ODBC drivers (except on Win32s, where you need 16-bit ODBC drivers). See the article ODBC Driver List for a list of ODBC drivers included in this version of Visual C++ and for information about obtaining additional drivers.

  • Microsoft Excel version 3.0, 4.0, 5.0, and 7.0 worksheets.

  • Lotus® WKS, WK1, WK3, WK4 spreadsheets.

  • Text files.

External Data Access Choices

The MFC DAO classes give you two choices for accessing tables stored in external data sources. You can either:

  • Attach the tables to a Microsoft Jet (.MDB) database

    -or-

  • Open the external database directly.

Attaching Tables

When you attach a table, it is treated in most respects as if it were a Microsoft Jet database table in the current database — except that you can't modify the table's schema or open a table-type recordset on it. The connection information to the external data source is stored with the table definition, making it easy to open recordsets on the table. The data is still stored in the external data source, however. For information on attaching tables, see the article DAO External: Attaching External Tables.

Tip If you attach a table from within Microsoft Access, you can then use the table from MFC.

Opening External Databases Directly

When you open a table directly, you specify the connection information each time you open the external database. This can involve communication overhead. For information on opening tables directly, see the article DAO External: Opening External Databases Directly.

Important In most cases, attaching a table is a faster method for accessing external data than opening a table directly, especially when the table is in an ODBC data source. If possible, it's best to attach external tables rather than to open them directly. If you do open a table in an ODBC data source directly, keep in mind that performance will be significantly slower.

To attach or open a data source on a network, you must have access to the server and share and to the external table as well as appropriate permissions for access to the data, if applicable.

Performance Considerations with External Data

Keep in mind that external tables are not actually in your Microsoft Jet database. Each time you view data in an external table, your program must retrieve records from another file. This can take time, particularly if the table is an ODBC data source.

ODBC performance is optimal if you attach tables instead of opening them directly, and if you retrieve and view only the data you need. Restrict your queries to limit results and avoid excessive scrolling through records. For more performance tips, see the article DAO External: Improving Performance with External Data Sources.

For a discussion of why performance suffers with external data sources, particularly ODBC data sources, see the topic "Accessing External Databases with DAO" in DAO Help.

When You Might Need to Open an External Table Directly

Attaching external tables to a Microsoft Jet database is generally more efficient than opening the external data source directly. However, there still might be circumstances under which you would prefer to open the external database directly. They include the following:

  • Non-ODBC external data sources give faster performance if you open them directly. Only ODBC is slower when opened directly.

  • You need to enumerate the tables in the external data source to find out the database structure at run time. Unless you know the table names, you can’t attach them.

  • You need to manipulate the table’s structure. You can’t modify the schema of an attached table.

Other Articles About Accessing External Data

For more information, including procedures, see the following articles (in the recommended reading order):

  • DAO External: Attaching External Tables

  • DAO External: Creating an External Table

  • DAO External: Refreshing and Removing Links

  • DAO External: Improving Performance with External Data Sources

For More Information About Accessing External Data

An additional source of information is the Advanced Topics book from the Microsoft Access Developer's Toolkit. You'll need to translate Microsoft Access Basic examples to MFC, but the chapter on Accessing External Data gives detailed advice on using external data sources such as Microsoft FoxPro, dBASE and Paradox.

For related information, see the topic "Accessing External Databases with DAO" in DAO Help.

For information about accessing specific external data sources, see the following topics in DAO Help:

  • Accessing Data in ODBC Databases with DAO

  • Accessing Data in a dBASE Database with DAO

  • Accessing Data in a Microsoft Excel Worksheet or Workbook with DAO

  • Accessing Data in a Microsoft FoxPro Database with DAO

  • Accessing Data in a Lotus Spreadsheet with DAO

  • Accessing Data in a Paradox Database with DAO

  • Accessing Data in a Text Document with DAO

  • Accessing Data on CD-ROM with DAO

See Also DAO: Where Is...


DAO External: Attaching External Tables

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to attach a table from an external data source, such as an ODBC data source, to your current Microsoft Jet (.MDB) database. Attaching external tables is generally more efficient than opening them directly, as explained in the article DAO External: Working with External Data Sources.

Important For performance reasons, it is best to attach tables in ODBC data sources rather than to open them directly. You can open non-ODBC external data sources directly if you like.

Tip If you attach a table from within Microsoft Access, you can then use the table from MFC.

To attach an external table using the MFC DAO classes

  1. Open your Microsoft Jet (.MDB) database (the one to which you'll attach the external table):

    Construct a CDaoDatabase object, or obtain a pointer to one (from an open recordset object, for example) and call the object's Open member function.

  2. Using the CDaoDatabase object, create a new CDaoTableDef object. Construct the tabledef object, then call its Create member function.

    In the Create call, you can specify the source table name and the connect string. Or you can accept the defaults in Create and separately call SetConnect and SetSourceTableName to specify the connect string and the name of the table as it appears on the data source. The example following this procedure calls SetConnect and SetSourceTableName.

  3. Attach the external table by appending it to the CDaoDatabase object's TableDefs collection.

    Call the tabledef object's Append member function.

  4. Use the attached table as if it were actually a table in the Microsoft Jet database.

    You can do the following, among other things:

    • Use the table to create a recordset.

    • Examine fields and indexes in the table.

    • Get or set validation conditions for the table.

The following example illustrates how to attach an external table:

// Construct the database and the tabledef
CDaoDatabase db;
db.Open("C:\\datatbase\\theDB.mdb");

// Construct the tabledef then create attached table
CDaoTableDef td( &db );
td.Create( "Preferred Customers", 0, "Customers",
"ODBC;DSN=afx;UID=sa;PWD=Fred" );

// Attach the tabledef to the external data source
td.Append( );

// Use td ...

The parameters to create are the tabledef name, attributes, source table name, and connect string.

Your link to the attached table remains active unless you delete the tabledef object or move the source table. If you move the source table, you can refresh the link using the tabledef object's RefreshLink member function.

Note For the external indexed sequential access method (ISAM) databases, such as FoxPro and dBASE, specify the full path to the directory in which the database files are located when a database name is called for.

Tip Because a tabledef object name can be any valid Microsoft Access table name, you can give the attached table a more descriptive name than is often allowed in the external data source. For example, if you attach an external dBASE table named SLSDATA, you can rename the attached table as “Sales Data 1995 (from dBASE).” The code in the previous example illustrates this.

See Also DAO: Where Is..., DAO External: Working with External Data Sources, DAO External: Opening External Databases Directly


DAO External: Opening External Databases Directly

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to open a table in an ODBC data source directly, rather than by attaching the table to a Microsoft Jet (.MDB) database. For a general discussion of external data sources, see the article DAO External: Working with External Data Sources.

Important If you are working with an ODBC data source, it is recommended that you attach the external table to your Microsoft Jet database instead of opening it directly as described in this article. Doing so significantly improves performance. For information about attaching tables, see the article DAO External: Attaching External Tables.

To open an external table directly using the MFC DAO classes

  1. Open the external data source.

    Construct a CDaoDatabase object, or obtain a pointer to one (from an open recordset object, for example) and call the object's Open member function. Supply appropriate connection information for the data source.

  2. Create a recordset for the external table.

    Construct a CDaoRecordset object, basing the recordset on the CDaoDatabase object for the external table.

  3. Work with the recordset as you would with any recordset. But note that if you are working with ODBC performance may not be as good as if you had attached the table instead.

Note Creating the recordset requires that you supply the external table name. Usually, you'll do this when you create your CDaoRecordset-derived class with either AppWizard or ClassWizard. The external table name is a table name, not a filename, so you don't use the filename extension. This is true for all external data sources, such as dBASE and FoxPro, in which tables are stored as individual disk files.

Important When you specify the recordset type (table-type, dynaset-type, or snapshot-type), be aware that you can't use a table-type recordset with ODBC data sources.

For information about the preferred alternative to this procedure, see the article DAO External: Attaching External Tables.

See Also DAO: Where Is..., DAO External: Working with External Data Sources, DAO External: Attaching External Tables


DAO External: Creating an External Table

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to create a new table, with the correct format, in an external data source. For general information about external data sources, see the article DAO External: Working with External Data Sources.

To create an external table

  1. Open the external database directly.

    Construct a CDaoDatabase object and call its Open member function. Pass the appropriate connection information.

    You can’t manipulate the schema of an attached table, so you must open directly.

  2. Create a tabledef for the new table.

    Construct a CDaoTableDef object based on the CDaoDatabase object. Call the tabledef object’s Create member function, specifying connection information and the name of the source table on which the tabledef is based.

    As an alternative, you could accept the default parameter values in Create, then call SetConnect and SetSourceTableName.

  3. Add fields to the new table.

    Call the tabledef object's CreateField member function. The new field is automatically appended to the underlying DAO tabledef object's Fields collection.

  4. Create the external data file by appending the tabledef object to the CDaoDatabase object's TableDefs collection.

See Also DAO: Where Is..., DAO External: Working with External Data Sources, DAO External: Attaching External Tables, DAO External: Refreshing and Removing Links


DAO External: Refreshing and Removing Links

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to refresh or remove a link to an attached table when the table has moved. For background, see the article DAO External: Attaching External Tables.

To refresh a link

  1. Reset the table's connection information ? that is, change the path to the external data source.

    Call the SetConnect member function for the saved tabledef object representing the attached table.

  2. Call the tabledef object's RefreshLink member function.

To remove a link to an attached table

  • In the CDaoDatabase object for your Microsoft Jet (.MDB) database, call the DeleteTableDef member function. Specify the name of the external table (the tabledef name).

Important When you delete an attached table, only the link is deleted. The external table itself is unaffected.

See Also DAO: Where Is..., DAO External: Working with External Data Sources, DAO External: Attaching External Tables, DAO External: Creating an External Table


DAO External: Improving Performance with External Data Sources

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains some things you can do to improve performance when you connect to external data sources, such as ODBC data sources. For general information about external data sources, see the article DAO External: Working with External Data Sources.

Improving Performance with ODBC Data Sources

If you're connecting to an ODBC data source, the following guidelines apply:

  • Use attached tables instead of directly opened tables whenever possible.

    See the article DAO External: Working with External Data Sources and the topic "Accessing External Databases with DAO" in DAO Help.

    Important This recommendation has the most significant impact on performance of all the recommendations in this list.

  • Retrieve and view only the data you need.

    Use restricted queries to limit the number of records you retrieve, and select only the columns you need. This requires transferring less data across the network.

    Don't use dynaset-type recordsets if you're not updating the data.

    Use forward-scrolling snapshot-type recordsets if you're only scrolling forward. Don't scroll through records unnecessarily, and avoid jumping to the last record of a large table.

  • Use caching.

    In class CDaoRecordset, MFC supports caching a specified number of records. Doing so takes longer initially, when the data is retrieved into the cache, but moving through the records in the cache is faster than retrieving each record as it is scrolled to.

  • Turn off the double-buffering option in MFC CDaoRecordset objects.

    This is a general way to improve performance that applies as well to working with external data sources.

  • For bulk operations, such as adding records in bulk, use an SQL pass-through query. Call SetConnect for the CDaoDatabase representing your .MDB database. Then call the database object’s Execute member function, or create a recordset, with the dbSQLPassThrough option set. For more information about pass-through queries, see the article DAO Querydef: Action Queries and SQL Pass-Through Queries. (You only need to set the connection information once, if you are always performing your SQL pass-through queries through the same connection.)

  • Avoid using queries that cause processing to be done locally.

    Don't use user-defined functions with remote column arguments. Use heterogeneous joins (joins on tables in two databases) only on indexed columns, and realize if you do this that some processing is done locally. When accessing external data, the Microsoft Jet database engine processes data locally only when the operation can't be performed by the external database. Query operations performed locally include:

    • WHERE clause restrictions on top of a query with a DISTINCT predicate.

    • WHERE clauses containing operations that can't be processed remotely, such as user-defined functions that involve remote columns. (Note that in this case only the parts of the WHERE clause that can't be processed remotely will be processed locally.)

    • Joins between tables from different data sources.

    Note Simply having joins between tables from different data sources doesn't mean that all of the processing occurs locally. If restrictions are sent to the server, only relevant rows are processed locally.

    • Joins over aggregation or the DISTINCT predicate.

    • Outer joins containing syntax not supported by the ODBC driver.

    • DISTINCT predicates containing operations that can't be processed remotely.

    • ORDER BY arguments (if the remote data source doesn't support them).

    • ORDER BY or GROUP BY arguments containing operations that can't be processed remotely.

    • Multiple-level GROUP BY arguments, such as those used in reports with multiple grouping levels.

    • GROUP BY arguments on top of a query with a DISTINCT option.

    • Cross-tab queries that have more than one aggregate or that have an ORDER BY clause that matches the GROUP BY clause.

    • TOP or TOP PERCENT predicate.

See Also DAO: Where Is..., DAO External: Working with External Data Sources, DAO External: Attaching External Tables


DAO Queries

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains what a query is and how to create and run one using the MFC DAO classes. Topics include:

  • Query: definition

  • Querydefs and recordsets

  • Creating a query with a querydef

  • Creating a query with a recordset

Query: Definition

A query is a formalized instruction to a database to either return a set of records or perform a specified action on a set of records as specified in the query. For example, the following SQL query statement returns records:

SELECT [Company Name] FROM Publishers WHERE State = "NY"

You can create and run select, action, crosstab, parameter, and other queries using the MFC DAO classes. Queries are expressed with Structured Query Language (SQL) statements like the one shown above. The most common query type is the SELECT query. For a list of other query types, see the topic "Type Property" in DAO Help, under Settings and Return Values listed for querydef objects.

How to Write SQL Statements

For general information on writing SQL queries, see the following topics in DAO Help:

  • Querying a Database with SQL in Code

  • Building SQL Statements in Code

Syntax of SQL Used with DAO

For a description of the SQL syntax used by DAO, see the topic "Comparison of Microsoft Jet Database Engine SQL and ANSI SQL" in DAO Help. For SQL syntax specific to your target database, see the documentation for your DBMS. For a list of additional topics on SQL in DAO Help, see the article DAO Queries: SQL for DAO.

Querydefs and Recordsets

You can work with queries in two ways:

  • Use a DAO querydef object ? the corresponding MFC object is represented by class CDaoQueryDef.

  • Use a DAO recordset object ? the corresponding MFC object is represented by class CDaoRecordset.

A querydef is a query definition, which you can optionally save as a persistent object in the database. A recordset is an object that represents and gives access to a set of records returned by a query.

Creating a Query with a Querydef

Once you create a querydef object, based on CDaoQueryDef, you can do the following with it:

  • Save the querydef object in the database, which lets you run its query again later.

  • Create parameters for the querydef, so you can run parameterized queries with it.

  • Create a recordset based on the querydef.

  • Use the querydef's Execute member function to directly execute a query that doesn't return records, such as an action query or a SQL pass-through query.

To create a querydef

  • See the detailed instructions in the article DAO Querydef: Using Querydefs.

Creating a Query with a Recordset

You can create a query with a recordset, represented by CDaoRecordset, in one of three ways:

  • First create or open a CDaoQueryDef object; then base a CDaoRecordset object on it, using the version of CDaoRecordset::Open that takes a pointer to a CDaoQueryDef object.

  • First create or open a CDaoTableDef object, then base a CDaoRecordset object on it, using the version of CDaoRecordset::Open that takes a pointer to a CDaoTableDef object.

  • Create a recordset, usually based on a class that you derive from CDaoRecordset using AppWizard or ClassWizard, and open the recordset. No querydef is required.

To create a recordset with or without a querydef or tabledef

  • See the article DAO Recordset: Creating Recordsets.

You’ll most likely base your recordsets on querydefs when you have a saved querydef for a query that you run frequently, or when you have just created a querydef that you plan to save in the database for later reuse. Or you’ll base recordsets on tabledefs when you have a tabledef and want to work with the data in the table that the tabledef represents. Otherwise, you’ll simply create a recordset (without a querydef) whenever you need one.

For related information, see the following topics in DAO Help:

  • QueryDef Object

  • Recordset Object

  • CreateQueryDef Method

See Also DAO: Where Is..., DAO Querydef, DAO Recordset


DAO Queries: SQL for DAO

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

SQL stands for Structured Query Language, the industry standard way to communicate with relational databases.

For information about SQL, see the topic "SQL Property" in DAO Help. For information about the SQL syntax used by DAO, see the topic "Comparison of Microsoft Jet Database Engine SQL and ANSI SQL" in DAO Help.

See Also DAO: Where Is..., DAO Querydef, DAO Recordset, DAO Queries


DAO Queries: Filtering and Parameterizing Queries

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes how to restrict the number of records that a query returns. Topics covered include:

  • Filtering recordsets

  • Parameterizing queries

One of the great keys to good database performance is to restrict how many records you select. In general, the more records you select, the greater the required memory and the slower the performance. DAO and MFC let you filter the records that a query selects, and you can specify filtering criteria at run time rather than design time. The mechanism works as follows:

  • Specify a filter for your query that restricts records using an SQL WHERE clause. For example:
    WHERE [State] = "NY"
  • Parameterizing specifies named parameters in the filter to which you can assign values at run time, based on information you calculate or obtain from the end-user. For example, the filter shown above looks like this with a named parameter:
    WHERE [State] = [State Code]

    State Code is the parameter name.

Filtering DAO Recordsets

Filtering records by any of the approaches described below relies on the SQL WHERE clause. You can also use the HAVING clause if you are using GROUP BY. For information about these keywords, see the following topics in DAO Help:

  • WHERE Clause (SQL)

  • HAVING Clause (SQL)

  • GROUP BY Clause (SQL)

And see the topic "SELECT Statement (SQL)" in DAO Help.

The MFC DAO classes let you filter a recordset in two ways:

  • You can specify an SQL statement for your recordset that lacks a WHERE clause, then supply a value at run time to the m_strFilter data member of your CDaoRecordset-derived class.

  • You can specify an SQL statement that includes a WHERE clause. In this case, you do not use m_strFilter.

Tip These two approaches are equivalent in terms of performance. The only difference is whether you build the WHERE clause in the SQL string that you use to create the recordset or you let MFC build the clause using a value you’ve supplied for m_strFilter.

Important You can’t use m_strFilter (or its companion m_strSort, which specifies an SQL ORDER BY clause for sorting) if you create your recordset from a CDaoTableDef or CDaoQueryDef object.

Example with m_strFilter

The following example shows filtering with m_strFilter (the first approach above):

// Filter records with m_strFilter but no parameter
// strStudentID is a value probably obtained from
// the user
rsEnrollmentSet.m_strFilter = "[Student ID] = " + strStudentID;
try
{
    // Open the recordset using the filtered string
    rsEnrollmentSet.Open( );
    // ...
}
// ...

MFC appends the value of m_strFilter to the recordset’s SQL as long as there is not a WHERE clause in the SQL string already.

Example with a Complete WHERE Clause

The following example shows filtering with a pre-specified WHERE clause (the second approach above):

// Filter records with the SQL keyword WHERE
CString strSQL = rsEnrollmentSet.GetDefaultSQL( ) +
             "WHERE [Student ID] = " + strStudentID;
try
{
    // Open the recordset using the filtered SQL string
    rsEnrollmentSet.Open( dbOpenDynaset, strSQL );
    // ...
}
// ...

The example calls GetDefaultSQL to obtain the SQL string defined for the recordset's class at design time, using ClassWizard or AppWizard. Then it concatenates a WHERE clause, part of which is based on run-time information in strStudentID.

In either case, the result is a recordset that contains a smaller number of records because of the filtering.

Note The filtering and sorting mechanisms described here are not available for table-type recordsets. To filter or sort records in a table-type recordset, you must call DAO directly. Set the Filter and Sort properties of the recordset. To specify which index (if any) is active for the recordset, call CDaoRecordset::SetCurrentIndex. For information about calling DAO directly, see Technical Note 54.

Parameterizing DAO Queries

In situations where your application executes the same query repeatedly, it is more efficient to create a stored querydef object that contains the SQL statement. Queries stored in the database execute faster and can be used by anyone with access to the database.

If your application needs to alter WHERE clause arguments in a query, you can also add a PARAMETERS clause to your query that permits the Microsoft Jet database engine to substitute values into the query at run time. Before running parameter queries, your application must substitute values for each of the parameters as stored in the Parameters collection of the querydef.

In general, parameterizing queries improves performance. The parameterized SQL statement doesn't have to be recompiled each time you run the query.

To create a parameter query

  1. Create a PARAMETERS clause string that includes a parameter name and data type for each parameter. Don't use the field name alone as the parameter name, because duplicating it may cause problems. You can include the field name within the parameter name, however. The example calls the parameter "Student Ident" rather than "Student ID", the name of the field.

    If you are working with a database accessed by Microsoft Access, the parameter name is used as a prompt string. Keep this in mind if you expect Microsoft Access users to use this query.

    Shown below is a typical PARAMETERS clause:

    CString strParam = "PARAMETERS [Student Ident] TEXT; ";

    The parameter name is enclosed in square brackets here because the name contains a space. Otherwise the brackets are unnecessary.

  2. Create a SELECT statement that retrieves the needed fields and incorporates the named parameters into the WHERE clause. In the example below, the parameters are used to filter the query to return only selected students. Note that the parameter [Student Ident] is substituted by the database engine during execution of the query at run time.
    strSQL = strParam + "SELECT * FROM Enrollment WHERE Enrollment.[Student ID] = [Student Ident]";
  3. Create a named querydef ("Find Enrollments") with your SQL statement.
    CDaoQueryDef qd( m_dbStudentReg );
qd.Create( "Find Enrollments", strSQL );
qd.Append( );
  4. Set the querydef parameters.

    First, you need to gain access to the querydef. You can either use the querydef object just created, or reference the stored querydef object from the QueryDefs collection. The example shows using the querydef just created.

    COleVariant varParamValue( strStudentID );
qd.SetParamValue( "[Student ID]", varParamValue );
  5. Execute the procedure.

    Because this query returns records, you need to create a recordset to capture the result set.

    CEnrollmentSet rsEnrollmentSet( &m_dbStudentReg );
rsEnrollmentSet.Open( &qd, dbOpenDynaset );

The parameter is defined as part of the SQL statement and becomes part of a PARAMETERS clause. You set the value of the parameter, at run time, by calling the querydef object's SetParamValue member function. This function takes:

  • A parameter name, which must match the name you specified in the SQL string ("Student Ident" in the example).

  • A COleVariant object that contains the value. COleVariant makes it easy to use the VARIANT data type from MFC for a variety of different actual types. In the example, the actual type is a string.

For more information and a different example (presented in the Basic language rather than C++), see the topic "Creating Parameter Queries with DAO" in DAO Help.

In the Class Library Reference, see CDaoQueryDef and CDaoRecordset. In particular, see CDaoQueryDef::SetParamValue and CDaoQueryDef::GetParamValue.

What do you want to know more about:

  • DAO Queries

  • DAO Querydef

  • DAO Recordset

  • DAO Queries: SQL for DAO

See Also DAO: Where Is...


DAO Querydef

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes “querydefs” and the key features of the MFC CDaoQueryDef class. For task-oriented information, see the article DAO Querydef: Using Querydefs. For an understanding of the DAO querydef object underlying each MFC CDaoQueryDef object, see the topic "QueryDef Object" in DAO Help.

Topics covered include:

  • Querydef: definition

  • Querydef uses

  • Querydef parameters

  • Querydefs and DAO collections

  • Further reading about querydefs

Querydef: Definition

A DAO querydef, represented in MFC by a CDaoQueryDef object, is a query definition. The object defines the SQL statement for a query and provides operations for executing the query, for saving it in the database for reuse, for parameterizing the query, and more.

For information about specifying a query with SQL, see the article DAO Queries.

Saved queries are advantageous because you can keep frequently used queries, especially complex ones, for easy reuse later. For information about saving querydefs in a database, see the article DAO Querydef: Using Querydefs.

Tip If you are working with Microsoft Jet (.MDB) databases, the easiest way to create a querydef is to do it in Microsoft Access. Open your target database, create querydefs, and save them in the database. Then you can use the querydefs in your code.

Querydef Uses

Querydef objects have two primary uses, corresponding to two ways to run the query:

  • Creating recordsets, which you then open to run the query.

  • Directly executing queries that don't return records. These include action queries and some SQL pass-through queries (those that return no records).

For information about these querydef uses, see the article DAO Querydef: Using Querydefs. For information about action queries and SQL pass-through queries, see the article DAO Querydef: Action Queries and SQL Pass-Through Queries.

QueryDef Parameters

Sometimes you'd like to be able to select records using information you've calculated or obtained from your user at run time. Parameterized queries let you pass such information at run time.

A query parameter is an element containing a value that you can change to affect the results of the query. For example, a query returning data about an employee might have a parameter for the employee's name. You can then use one querydef object to find data about any employee by setting the parameter to a specific name before running the query. This has two valuable effects:

  • It can result in better execution speed, particularly on the second and subsequent requeries.

  • It lets you build a query at run time, based on information not available to you at design time, such as information that you must obtain from the user or information that you must calculate.

Important In DAO, the parameter names are exposed rather than only the positions as in ODBC. While ODBC does allow named parameters, users of the MFC ODBC classes will be more familiar with using positional parameters.

For more information about DAO parameters, see the following topics in DAO Help:

  • Parameter Object, Parameters Collection Summary

  • Creating Parameter Queries with DAO

  • PARAMETERS Declaration (SQL)

For more information about using parameterized queries, see the article DAO Queries: Filtering and Parameterizing Queries.

QueryDefs and DAO Collections

Each DAO database object maintains a QueryDefs collection — a collection of all saved querydefs in the database. Each querydef object maintains two collections of its own:

  • Parameters. All defined parameters for the query.

  • Fields. The fields in one or more tables that correspond to the parameters. For example, an Employee Name field corresponds to an Employee Name parameter.

MFC objects don't store a representation of a DAO collection. Instead, MFC accesses the collection through the underlying DAO object. For more information, see the article DAO Collections.

MFC also doesn't provide a C++ class to represent every DAO object. In particular, there is no MFC parameter object or field object. You work with a querydef's parameters and fields through member functions of class CDaoQueryDef. For more information, see the article DAO Queries: Filtering and Parameterizing Queries.

Further Reading About Querydefs

For more information about querydefs in MFC, see the following additional articles (in the recommended reading order):

  • DAO Queries

  • DAO Querydef: Using Querydefs

  • DAO Queries: Filtering and Parameterizing Queries

  • DAO Querydef: Action Queries and SQL Pass-Through Queries

See Also DAO: Where Is..., DAO Recordset


DAO Querydef: Using Querydefs

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to use CDaoQueryDef objects. Topics covered include:

  • Creating a querydef

  • Saving a querydef (in Microsoft Jet (.MDB) databases only)

  • Opening a previously saved querydef

  • Using a temporary querydef

  • Creating a recordset from a querydef

  • Directly executing a query (an action query or an SQL pass-through query that doesn't return records)

For a general understanding of querydefs and their uses, see the topic "QueryDef Object" in DAO Help.

Creating a Querydef

Creating a querydef, whether you save it in the database or use it as a temporary object, requires specifying the SQL statement that defines the query and setting any needed properties of the querydef. If the querydef represents a parameterized query, you also need to create the parameters and their corresponding fields and later set their values.

Tip You can also set and get field values and parameter values (in a recordset) dynamically, without using a querydef. See the article DAO Recordset: Binding Records Dynamically.

Creating a new MFC CDaoQueryDef object creates the underlying DAO querydef object.

To create a querydef

  1. Construct a CDaoQueryDef object.

  2. Call the querydef object's Create member function.

    In the Create call, pass a user-defined name for the querydef and a string that contains the SQL statement on which the querydef is based. While you can define the SQL string for a recordset with AppWizard or ClassWizard, you must write the SQL string for a querydef yourself. (You usually use class CDaoQueryDef directly rather than deriving your own querydef classes from it.)

  3. Save the querydef object in the database by calling its Append member function, unless you want to work with a temporary (unsaved) querydef. (See Using a Temporary Querydef.)

  4. Either create a recordset based on the querydef or call the querydef object's Execute member function.

Close the querydef when you finish with it. Call its Close member function. For more information, see the detailed instructions under CDaoQueryDef::Create in the Class Library Reference.

Querydef objects have several properties you can set — primarily for querydefs to be used with ODBC data sources.

To set a querydef's properties (primarily for ODBC)

  1. Create the querydef, using a CDaoQueryDef object, as described above.

  2. Call any of the following member functions: SetConnect, SetODBCTimeout, SetReturnsRecords, SetName, SetSQL.

  3. Save the querydef in the QueryDefs collection by calling Append, unless you want to use the querydef as a temporary object. (See Using a Temporary Querydef.)

  4. Use the querydef.

You can use SetName and SetSQL for a querydef based on any kind of database. You can call these member functions at any time to rename the querydef object or to respecify its SQL statement. SetReturnsRecords applies only to SQL pass-through queries. The other functions apply only to ODBC data sources.

After creating a querydef, you will usually want to save it in the database by appending it to the QueryDefs collection. See Saving a Querydef. The alternative is to use the querydef as a temporary object. See Using a Temporary Querydef. You can’t use the querydef unless you correctly create it as a temporary querydef or you append it to the collection.

Once created, use the querydef to create recordsets or to execute action queries or SQL pass-through queries. For information about action queries and SQL pass-through queries, see the article DAO Querydef: Action Queries and SQL Pass-Through Queries.

Saving a Querydef

A saved querydef persists in its database (.MDB only), stored there along with the database's tables and data. You can think of a saved query as a compiled SQL statement — when you run the query, it executes faster than a standard new query because the database engine doesn't have to compile the SQL statement before executing it.

Tip The easiest way to create a querydef is to do it in Microsoft Access. Open your target .MDB database, create querydefs, and save them in the database. Then you can use the querydefs in your code.

To save a querydef

  1. Create the querydef as described under Creating a Querydef.

  2. Call CDaoQueryDef::Append for the object.

Appending the querydef object to the database's QueryDefs collection makes the object persistent between database engine sessions. You can open and run the query, or modify it, at any time. Other users of your database can use the querydef as well.

The alternative to saving a querydef is using it as a temporary object.

Opening a Previously Saved Querydef

Once you’ve saved a querydef in a database’s QueryDefs collection, you can open it at any time and run its query, either by creating a recordset or by calling Execute.

To open a saved querydef

  1. Construct a CDaoQueryDef object.

  2. Call its Open member function.

    In the Open call, pass the user-defined name under which the querydef was stored.

Using a Temporary Querydef

A temporary querydef object has the following characteristics:

  • It is never appended to the QueryDefs collection in the database, unlike a saved querydef.

  • It is created by passing either NULL or an empty string for the querydef’s name.

Note MFC differs from the underlying DAO implementation in the way querydefs are appended to the collection. In DAO, a newly created querydef (provided you give it a name) is automatically appended to the QueryDefs collection. In MFC, you must explicitly call Append.

Saved querydefs are accessible to other users of your database (who have the appropriate permissions, if security is in effect). Temporary querydefs are not accessible to other users. In some cases, you might want to create a querydef and use it without storing it. For example, you might want to use querydef parameters but not want to save the querydef for reuse.

Whether a querydef is temporary or not depends on what you pass in the lpszName parameter to Create. Querydefs can be in one of the states listed in the following table.

QueryDef States and Their Meanings

State | Meaning
Appended | You give the querydef a name when you create it. Then you call Append.
Unappended | You give the querydef a name but you haven’t called Append. The querydef is unusable. This is not the same thing as a temporary querydef.
Temporary | You pass NULL or an empty string (“”) for the querydef name when you create the querydef. You can’t append a temporary querydef, because it has no name. But you can use it to create recordsets or to call the Execute member function.

The following procedure explains how to create temporary querydefs.

To create a temporary querydef

  1. Construct a CDaoQueryDef object.

  2. Call its Create member function, passing NULL or an empty string (“”).

  3. Don't call CDaoQueryDef::Append.

You can still use a temporary querydef to create recordsets or to execute action queries or SQL pass-through queries.

Creating a Recordset from a Querydef

The most common way to use a querydef is to base a recordset on it. The recordset inherits the querydef's SQL statement.

To create a recordset from a querydef

  1. Create a saved or temporary querydef as described in Creating a Querydef, or open a previously saved querydef.

  2. Construct a CDaoRecordset object.

  3. Call the recordset object's Open member function, passing a pointer to your querydef object.

Calling Open runs the query. For a more detailed discussion, see the article DAO Recordset: Creating Recordsets.

You can create any number of recordsets from the same querydef object. They will all have the same SQL statement unless you change the querydef's SQL statement between creating recordsets.

For related information, see the article DAO Queries.

Executing a Querydef

Not all queries return records. Queries that don't return records include:

  • Action queries, which update data or alter the database's structure.

  • SQL pass-through queries, which pass the SQL statement to the back-end DBMS without processing it in the Microsoft Jet database engine.

To execute such queries, you use a querydef rather than a recordset. For more information about action queries and SQL pass-through queries, see the article DAO Querydef: Action Queries and SQL Pass-Through Queries.

To directly execute a query that doesn't return records

  1. Create a saved or temporary querydef as described in Creating a Querydef.

  2. Call the querydef's Execute member function.

For more information about executing queries, see CDaoQueryDef::Execute in the Class Library Reference and the topic "Execute Method" in DAO Help.

What do you want to know more about?

  • DAO Querydef

  • DAO Recordset

  • DAO Queries

  • DAO Querydef: Action Queries and SQL Pass-Through Queries

See Also DAO: Where Is...


DAO Querydef: Action Queries and SQL Pass-Through Queries

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article tells you where to find information about action queries and SQL pass-through queries.

For information about action queries, including a definition, see the following topics in DAO Help:

  • Action Query

  • Querying a Database with SQL in Code

For information about SQL pass-through queries, including a definition, see the following topics in DAO Help:

  • Using SQL PassThrough with DAO

  • QueryDef Object

Quick SQL Pass-Through Queries

The fastest way to work with ODBC data sources is via attached tables. See the article DAO External: Working with External Data Sources. For doing bulk operations, the best, and often fastest, approach is to use an SQL pass-through query. It’s possible to do a quick pass-through query using a recordset and without having to create a querydef, even a temporary one. This is also helpful if you’re converting existing code that uses the DB_SQLPASSTHROUGH option in many places.

DAO’s Connect property for databases normally doesn’t have a value for Microsoft Jet (.MDB) databases. But you can assign an ODBC connect string to the property and use the dbSQLPassthrough option in a recordset. This means you don’t have to open the ODBC data source directly to use SQL pass-through.

For example:

// pdb is a pointer to a CDaoDatabase object
// (an .MDB database)
// Set up the connect string
CString strConnect = "ODBC;DSN=ntstuff;UID=sa;PWD=Fred;APP=App Name;WSID=MyComputer;DATABASE=pubs;TABLE=dbo.authors;";
pdb->SetConnect( strConnect );
// Use SQL pass-through in a recordset
// Set up the SQL and open the recordset
CString strSQL = "whatever";
CDaoRecordset rs( pdb );
try
{
    rs.Open( dbOpenSnapshot, strSQL, dbSQLPassThrough );
    // ...
}
// ...

What do you want to know more about?

  • DAO Querydef

  • DAO Querydef: Using Querydefs

See Also DAO: Where Is..., CDaoQueryDef::Execute


DAO Record Field Exchange (DFX)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The MFC DAO database classes automate moving data between the data source and a recordset using a mechanism called “DAO record field exchange” (DFX). DFX is similar to dialog data exchange (DDX) and, at the interface level, almost identical to record field exchange (RFX) for the MFC ODBC classes. If you understand RFX, you will find DFX easy to use.

Note The MFC DAO database classes are distinct from the MFC database classes based on ODBC. All DAO class names have the "CDao" prefix. Where the ODBC classes are based on Open Database Connectivity (ODBC), the DAO classes are based on Data Access Objects (DAO), which use the Microsoft Jet database engine. In general, the MFC DAO classes have more capabilities than the MFC ODBC classes. For more information, see the article DAO and MFC.

The DoFieldExchange Mechanism for DAO

Moving data between a data source and the field data members of a recordset requires multiple calls to the recordset’s DoFieldExchange function and considerable interaction between the framework and DAO. The DFX mechanism is type-safe and saves you the work of allocating storage and binding data to it. Sometimes, however, there will be a performance penalty for this ease of use. (For more information about DDX, see Dialog Data Exchange and Validation.)

Derived Recordset Classes for DAO

DFX is mostly transparent to you. If you declare your recordset classes with AppWizard, ClassWizard, WizardBar, or ClassView, DFX is built into them automatically. DAO recordset classes are normally derived from the base class CDaoRecordset supplied by the framework (but see Using CDaoRecordset Directly Instead of Deriving). AppWizard lets you create an initial recordset class. ClassWizard, WizardBar, and ClassView let you add other recordset classes as you need them. You use the wizards to map recordset field data members to table columns on the data source. For more information and examples, see the article ClassWizard: Creating a Recordset Class.

You must manually add a small amount of DFX code in two cases — when you want to:

  • Use parameterized queries. See the article DAO Queries: Filtering and Parameterizing Queries.

  • Perform joins — using one recordset for columns from two or more tables, joined on a common field by a WHERE clause in the SQL statement such as:
    WHERE Course.CourseID = Section.CourseID

Using CDaoRecordset Directly Instead of Deriving

There is an alternative to using DFX (and derived CDaoRecordset classes). You can use CDaoRecordset directly (without deriving from it) to bind a specified field in the current record dynamically. For more information, see the article DAO Recordset: Binding Records Dynamically.

More Information About DFX

If you need a more advanced understanding of DFX, see the article DAO Record Field Exchange: How DFX Works.

The following articles explain the details of using recordset objects:

  • DAO Record Field Exchange: Using DFX

  • DAO Record Field Exchange: Working with the Wizard Code

  • DAO Record Field Exchange: Using the DFX Functions

See Also DAO: Where Is..., DAO Recordset, ClassWizard: Creating a Recordset Class, Overview: Creating a Program That Supports a Database, CDaoFieldExchange


DAO Record Field Exchange: Using DFX

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains what you do to use DFX in relation to what the framework does. The related article, DAO Record Field Exchange: Working with the Wizard Code, continues the discussion. That article introduces the main components of DFX and explains the code that the wizards write to support DFX and how you might want to modify the wizard code.

Note This article is about the DAO version of record field exchange. If you are using the MFC ODBC classes rather than the MFC DAO classes, see the article Record Field Exchange: Using RFX instead.

Writing calls to the DFX functions in your DoFieldExchange override is explained in the article DAO Record Field Exchange: Using the DFX Functions.

The following table shows your role in relation to what the framework does for you.

Using DFX: You and the Framework

You... | The framework...
Declare your recordset classes with ClassWizard. Specify names and data types of field data members. | ClassWizard derives a CDaoRecordset class and writes a DoFieldExchange override for you, including a DFX function call for each field data member.
(Optional) Manually add any needed parameter data members to the class. Manually add a DFX function call to DoFieldExchange for each parameter data member, add a call to CDaoFieldExchange::SetFieldType for the group of parameters, and specify the total number of parameters in m_nParams. (See DAO: Filtering and Parameterizing Queries for an alternative way to parameterize queries.) |
Construct an object of your recordset class. Then, before opening the object, set the values of its parameter data members, if any. (If you create your recordset from a querydef object, you can specify parameters in the querydef.) | For efficiency, the framework prebinds the parameters, using DAO. When you pass parameter values, the framework passes them to the DAO data source. Only the parameter values are sent for requeries, unless the sort and/or filter strings have changed.
Open a recordset object using CDaoRecordset::Open. | Executes the recordset’s query, binds columns to field data members of the recordset, and calls DoFieldExchange to exchange data between the first selected record and the recordset’s field data members.
Scroll in the recordset using CDaoRecordset::Move or a menu or toolbar command. | Calls DoFieldExchange to transfer data to the field data members from the new current record.
Add, update, and delete records. | Calls DoFieldExchange to transfer data to the database.

For related information, see class CDaoFieldExchangeand Record Field Exchange Functions.

See Also DAO: Where Is..., DAO Record Field Exchange (DFX), DAO Record Field Exchange: How DFX Works, DAO Recordset


DAO Record Field Exchange: Working with the Wizard Code

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the code that the wizards write to support DFX and how you might want to alter that code.

Note This article is about the DAO version of record field exchange. If you are using the MFC ODBC classes rather than the MFC DAO classes, see the article Record Field Exchange: Working with the Wizard Code instead.

When you create a recordset class with a wizard, the wizard writes the following DFX-related elements for you, based on the data source, table, and column (field) choices you make in the wizard:

  • Declarations of the recordset field data members as described in the article DAO Recordset: Architecture

  • An override of CDaoRecordset::DoFieldExchange

  • Initialization of recordset field data members in the recordset class constructor

The Field Data Member Declarations for DAO

The wizards write a recordset class declaration in an .H file that resembles the following for a user-defined class called CSectionSet:

class CSectionSet : public CDaoRecordset
{
public:
    CSectionSet(CDaoDatabase* pDatabase = NULL);
    DECLARE_DYNAMIC(CSectionSet)

// Field/Param Data
    //{{AFX_FIELD(CSectionSet, CDaoRecordset)
    CString    m_CourseID;
    CString    m_SectionNo;
    CString    m_InstructorID;
    CString    m_RoomNo;
    CString    m_Schedule;
    int        m_Capacity;
    //}}AFX_FIELD

// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CSectionSet)
    public:
    virtual CString GetDefaultDBName();
    virtual CString GetDefaultSQL();
    virtual void DoFieldExchange(CDaoFieldExchange*
                                                  pFX);
    //}}AFX_VIRTUAL

// Implementation
#ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
#endif

};

Notice the following key features about the class above:

  • Special “//{{AFX_FIELD” comments that bracket the field data member declarations. ClassWizard uses these to update your source file.

  • The wizard overrides several CDaoRecordset virtual functions. The most important of these is the DoFieldExchange member function.

Caution Never edit the code inside “//{{AFX” brackets. Always use ClassWizard. If you add parameter data members or new field data members that you bind yourself, add them outside the brackets.

The DoFieldExchange Override for DAO

DoFieldExchange is the heart of DFX. The framework calls DoFieldExchange any time it needs to move data either from data source to recordset or from recordset to data source. DoFieldExchange also supports obtaining information about field data members through the IsFieldDirty and IsFieldNull member functions.

The following DoFieldExchange override is for a user-defined CSectionSet class. ClassWizard writes the function in the .CPP file for your recordset class.

void CSectionSet::DoFieldExchange(CDaoFieldExchange* pFX)
{
    //{{AFX_FIELD_MAP(CSectionSet)
    pFX->SetFieldType(CDaoFieldExchange::outputColumn);
    DFX_Text(pFX, _T("CourseID"), m_CourseID);
    DFX_Text(pFX, _T("SectionNo"), m_SectionNo);
    DFX_Text(pFX, _T("InstructorID"), m_InstructorID);
    DFX_Text(pFX, _T("RoomNo"), m_RoomNo);
    DFX_Text(pFX, _T("Schedule"), m_Schedule);
    DFX_Short(pFX, _T("Capacity"), m_Capacity);
    //}}AFX_FIELD_MAP
}

Notice the following key features of the function:

  • The special “//{{AFX_FIELD_MAP” comments. ClassWizard uses these to update your source file. This section of the function is called the “field map.”

  • A call to CDaoFieldExchange::SetFieldType, through the pFX pointer. This call specifies that all DFX function calls up to the end of DoFieldExchange or the next call to SetFieldType are “output columns.” See CDaoFieldExchange::SetFieldType in the Class Library Reference for more information.

  • Several calls to the DFX_Text and DFX_Short global functions — one per field data member. These calls specify the relationship between a column name on the data source and a field data member. The DFX functions do the actual data transfer. The class library supplies DFX functions for all of the common data types. For more information about DFX functions, see the article DAO Record Field Exchange: Using the DFX Functions and, in the Class Library Reference under Macros and Globals, Record Field Exchange Functions.

  • The pFX pointer to a CDaoFieldExchange object that the framework passes when it calls DoFieldExchange. The CDaoFieldExchange object specifies the operation that DoFieldExchange is to perform, the direction of transfer, and other context information.

  • The use of the _T macro for Unicode enabling. For more information, see the article Strings: Unicode and Multibyte Character Set (MBCS) Support.

The Recordset Constructor for DAO

The recordset constructor that the wizards write contains two things related to DFX:

  • An initialization for each field data member

  • An initialization for the m_nFields data member, which contains the number of field data members

The constructor for the CSectionSet recordset example looks like this:

CSectionSet::CSectionSet(CDaoDatabase* pdb)
    : CDaoRecordset(pdb)
{
    //{{AFX_FIELD_INIT(CSectionSet)
    m_CourseID = _T("");
    m_SectionNo = _T("");
    m_InstructorID = _T("");
    m_RoomNo = _T("");
    m_Schedule = _T("");
    m_Capacity = 0;
    m_nFields = 6;
    //}}AFX_FIELD_INIT
    m_nDefaultType = dbOpenDynaset;

    m_bCheckCacheForDirtyFields = TRUE;
}

This code initializes all of the field data members that require initialization and specifies how many field data members there are (in m_nFields). The code also sets the values of two special recordset data members:

  • m_nDefaultType Set to the type of recordset you specify in the wizard. All recordsets created from this class default to the type set here, but you can override the default for any particular recordset object by specifying a new type when you call CDaoRecordset::Open.

  • m_bCheckCacheForDirtyFields If set to TRUE (the default), the recordset uses a “double-buffering” mechanism to detect edits to fields by comparing them to a copy of the record. For more information, see the article DAO Record Field Exchange: Double Buffering Records.

Note The code above is enabled for Unicode.

Important If you add any field data members manually, you must increment m_nFields. Do so with another line of code outside the “//{{AFX_FIELD_INIT” brackets, such as:

    m_nFields += 3;

This is the code for adding three new fields. If you add any parameter data members, you must initialize the m_nParams data member, which contains the number of parameter data members. Put the m_nParams initialization outside the brackets.

For more information about these special recordset data members, see the article DAO Recordset: Architecture.

See Also DAO: Where Is..., DAO Record Field Exchange (DFX), DAO Record Field Exchange: Using DFX, DAO Record Field Exchange: How DFX Works, DAO Recordset, DAO Queries: Filtering and Parameterizing Queries


DAO Record Field Exchange: Using the DFX Functions

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to use the DFX function calls that make up the body of your DoFieldExchange override.

Note This article is about the DAO version of record field exchange. If you are using the MFC ODBC classes rather than the MFC DAO classes, see the article Record Field Exchange: Using the RFX Functions instead.

The DFX global functions exchange data between columns (fields) on the data source and field data members in your recordset. Normally you use ClassWizard to write the DFX function calls in your recordset’s DoFieldExchange member function. This article describes the functions briefly and shows the data types for which DFX functions are available. Technical Note 53 describes how to write your own DFX functions for additional data types.

DFX Function Syntax

Each DFX function takes three parameters (and some take an optional fourth or fifth parameter):

  • A pointer to a CDaoFieldExchange object. You simply pass along the pFX pointer passed to DoFieldExchange.

  • The name of the column (field) as it appears in the data source. The names in your SQL statement must match those in the DFX call. Advanced programmers might want to qualify the column names, for example by adding aggregate functions or other SQL modifications. For general guidelines, see the article Recordset: Obtaining SUMs and Other Aggregate Results (ODBC) (the article is for the MFC ODBC classes, but the general principles it illustrates apply as well to DAO). You can also add GROUP BY and other clauses to your SQL, either in the SQL statement or in the DFX function calls. The column (field) name, and any modifications to it, are used to build a query.

  • The name of the corresponding field data member or parameter data member in the recordset class.

  • (Optional) In some of the functions, which handle variable-length data, your specification of how much memory to preallocate for the data. For details, see DFX_Binary, DFX_Text, and DFX_LongBinary.

  • (Optional) A flag that specifies whether the field is to be double buffered. For more information, see DoFieldExchange and the article DAO Record Field Exchange: Double Buffering Records.

For more information, see Record Field Exchange Functions under Macros and Globals in the Class Library Reference.

DFX Data Types

The class library supplies DFX functions for transferring many different data types between the data source and your recordsets. The following list summarizes the DFX functions by data type. In cases where you must write your own DFX function calls, select from these functions by data type.

Data Types and DFX Functions

DFX function | C++ data type | DAO data type
DFX_Binary | CByteArray | DAO_BYTES
DFX_Bool | BOOL | DAO_BOOL
DFX_Byte | BYTE | DAO_BYTES
DFX_Currency | COleCurrency | DAO_CURRENCY
DFX_DateTime | COleDateTime | DAO_DATE
DFX_Double | double | DAO_R8
DFX_Long | long | DAO_I4
DFX_LongBinary | CByteArray or CLongBinary* | DAO_BYTES
DFX_Short | short | DAO_I2
DFX_Single | float | DAO_R4
DFX_Text | CString* | DAO_CHAR

Note Mapping long binary objects, such as pictures or OLE objects, to CByteArray is now preferred over mapping them to class CLongBinary. DFX_Text maps between CString and DAO_WCHAR if the symbol _UNICODE is defined. CByteArray gives you easier control over the contents of the long binary object.

Note You can use DFX to bring data of a DAO type into a variable of a different type as long as a conversion exists between the two. Take care, however, in cases such as converting a string to a date. If the string doesn’t parse to a correct date format, an error will result.

For information about the DAO data types in the third column of the table Data Types and DFX Functions, see the topic "Type Property" in DAO Help. For more information about the DFX functions in the first column of that table, see Record Field Exchange Functions under Macros and Globals in the Class Library Reference.

Also in the Class Library Reference see CDaoRecordset and CDaoFieldExchange.

See Also DAO: Where Is..., DAO Record Field Exchange (DFX), DAO Record Field Exchange: Using DFX, DAO Record Field Exchange: Working with the Wizard Code, DAO Record Field Exchange: Using the DFX Functions, DAO Record Field Exchange: How DFX Works, DAO Queries: Filtering and Parameterizing Queries, DAO Recordset


DAO Record Field Exchange: How DFX Works

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the DFX process. This is a fairly advanced topic, covering:

  • DFX and the recordset

  • The DFX process

Note This article is about the DAO version of record field exchange. If you are using the MFC ODBC classes rather than the MFC DAO classes, see the article Record Field Exchange: How RFX Works instead.

DFX and the Recordset

The recordset object’s field data members, taken together, constitute an edit buffer that holds the selected columns of one record. When the recordset is first opened and is about to read the first record, DFX binds (associates) each selected column to the address of the appropriate field data member. When the recordset updates a record, DFX calls DAO to send the appropriate commands to the database engine. DFX uses its knowledge of the field data members to specify the columns (fields) in the data source to write.

There are two ways of working with the edit buffer in a recordset:

  • Use MFC’s “double-buffering” mechanism.

    By default, your recordsets keep a second copy of the edit buffer for most data types (excluding the variable-length types, such as text and binary data). The copy is used for comparison with the edit buffer, to detect changes. You can choose to turn double buffering off, but keeping it turned on simplifies managing record field updates, adding and deleting records, and so on. For more information about double buffering, see the article DAO Record Field Exchange: Double Buffering Records.

  • Don’t use double buffering; instead, manage all field activity yourself.

    If you turn off the default double buffering, each time you edit a field you must call SetFieldDirty and SetFieldNull (passing the parameter FALSE). That is, you must take explicit actions so MFC does not have to compare the edit buffer with a copy to detect your changes. For more information, see the article DAO Record Field Exchange: Double Buffering Records.

If you have double buffering enabled (the default), the framework backs up the edit buffer at certain stages so it can restore its contents if necessary. With double buffering enabled, DFX backs up the edit buffer before adding a new record and before editing an existing record. It restores the edit buffer in some cases — for example, after an Update call following AddNew.

Besides exchanging data between the data source and the recordset’s field data members, DFX manages binding parameters. When the recordset is opened, any parameter data members are bound in the order of the named parameters in the SQL statement that CDaoRecordset::Open receives or constructs. For more information, see the article DAO Queries: Filtering and Parameterizing Queries.

Your recordset class’s override of DoFieldExchange does all the work, moving data in both directions. Like dialog data exchange (DDX), DFX needs information about the data members of your class. ClassWizard provides the necessary information by writing a recordset-specific implementation of DoFieldExchange for you, based on the field data member names and data types you specify with the wizard.

The DAO Record Field Exchange Process

This section describes the sequence of DFX events as a recordset object is opened and as you scroll and add, update, and delete records. The table Using DFX: You and the Framework in the article DAO Record Field Exchange: Using DFX shows the process at a high level, illustrating operations as a recordset is opened. The table Sequence of DFX Operations During Recordset Open and the table Sequence of DFX Operations During Scrolling in this article show the process as DFX processes a Move command in the recordset and as DFX manages an update. During these processes, DoFieldExchange is called to perform many different operations. The m_nOperation data member of the CDaoFieldExchange object determines which operation is requested.

DFX: Initial Binding of Columns and Parameters

The following DFX activities occur, in the order shown, when you call a recordset object’s Open member function:

  • If the recordset has parameter data members, the framework calls DoFieldExchange to bind the parameters to named parameters in the recordset’s SQL statement.

  • The framework calls DoFieldExchange a second time to bind the columns to corresponding field data members in the recordset. This establishes the recordset object as an edit buffer containing the columns of the first record.

  • The recordset opens either a table-type recordset or an SQL-based recordset (dynaset or snapshot) and selects the first record. The record’s columns are loaded into the recordset’s field data members.

The following table shows the sequence of DFX operations when you open a recordset.

Sequence of DFX Operations During Recordset Open

Your operation | DoFieldExchange operation | Database operation
1. Open the recordset. |  |
 | 2. Build an SQL statement. DoFieldExchange might have a querydef, a tabledef, or an SQL statement handed to it. If not, MFC builds the statement. |
 |  | 3. Open the querydef or tabledef, or create a temporary querydef (using either an SQL statement passed in or one built by MFC) and open it.
 | 4. Bind parameter data member(s). |
 | 5. Bind field data member(s) to column(s). |
 |  | 6. Create the recordset.
 |  | 7. DAO moves to the first record and fills in the data.
 | 8. Fix up the data for C++. |

DFX: Scrolling

When you scroll from one record to another, the framework calls DoFieldExchange to replace the values previously stored in the field data members with values for the new record.

The following table shows the sequence of DFX operations when the user moves from record to record.

Sequence of DFX Operations During Scrolling

Your operation | DoFieldExchange operation | Database operation
1. Call MoveNext or one of the other Move functions. |  |
 |  | 2. DAO does the move and fills in the data.
 | 3. Fix up the data for C++. |

DFX: Adding New Records and Editing Existing Records

If you add a new record, the recordset operates as an edit buffer to build up the contents of the new record. As with adding records, editing records involves changing the values of the recordset’s field data members. From the DFX perspective, the sequence is as follows:

  1. If double buffering is on, your call to the recordset’s AddNew or Edit member function causes DFX to store the current edit buffer so it can be restored later.

  2. If double buffering is on, AddNew or Edit prepares the fields in the edit buffer so DFX can detect changed field data members. If double buffering is off for an Edit call, the fields are not prepared for detection. (In this case, it’s up to you to manage edits explicitly — see the article DAO Record Field Exchange: Double Buffering Records.) The fields of a record prepared for AddNew are set to null whether double buffering is in effect or not.

    Since a new record has no previous values to compare new ones with, AddNew (with double buffering) sets the value of each field data member to a PSEUDO_NULL value as described under CDaoFieldExchange::m_nOperation. Later, when you call Update, DFX compares each data member’s value with the PSEUDO_NULL value; if there’s a difference, the data member has been set. (PSEUDO_NULL is not the same thing as a record column with a true Null value; nor is either the same as C++ NULL.)

    Note MFC does not use a PSEUDO_NULL value for COleDateTime or COleCurrency fields. Those data types have Nulls built in.

    Unlike the Update call for AddNew, the Update call for Edit compares updated values with previously stored values rather than using PSEUDO_NULL, if double buffering is on. If double buffering is off, you must call SetFieldDirty after an edit (and SetFieldNull if appropriate). The difference between Edit and AddNew is that AddNew has no previous stored values for comparison.

  3. You directly set the values of field data members whose values you want to edit or that you want filled for a new record. (This can include calling SetFieldNull.)

  4. If double buffering is on, your call to Update checks for changed field data members, as described in step 2 (see the table Sequence of DFX Operations During Scrolling). If none have changed, Update returns 0. If some field data members have changed, Update propagates the changes to the database.

  5. For AddNew, Update concludes by restoring the previously stored values of the record that was current before the AddNew call. For Edit, the new, edited values remain in place if double buffering is in effect.

The following table shows the sequence of DFX operations when you add a new record or edit an existing record.

Sequence of DFX Operations During AddNew and Edit

Your operation | DoFieldExchange operation | Database operation
1. Call AddNew or Edit. |  |
 | 2. Back up the edit buffer if double buffering is on. |
 | 3. For AddNew, mark field data members as “clean” and Null. For Edit, call Edit in DAO. |
4. Assign values to recordset field data members. |  |
5. Call Update. |  |
 | 6. Check for changed fields if double buffering is on. |
 |  | 7. Propagate changes to the database. Call Update in DAO.
 | 8. For AddNew, restore the edit buffer to its backed-up contents if double buffering is on. If it is off, the values set for the new record remain in the recordset data members. For Edit, delete the backup if double buffering is on. |
9. If double buffering is off, you must refresh the current record after AddNew. Call Move with the AFX_MOVE_REFRESH parameter to restore the record that was previously current. |  |

DFX: Deleting Existing Records

When you delete a record, DFX sets all the fields to NULL as a reminder that the record is deleted and you must move off it. You won’t need any other DFX sequence information.

In the Class Library Reference see CDaoFieldExchange, CDaoRecordset::DoFieldExchange, and, under Macros and Globals, Record Field Exchange Functions.

See Also DAO: Where Is..., DAO Record Field Exchange (DFX), DAO Record Field Exchange: Using DFX, DAO Record Field Exchange: Working with the Wizard Code, DAO Record Field Exchange: Using the DFX Functions, ClassWizard


DAO Record Field Exchange: Double Buffering Records

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the double buffering mechanism that MFC uses to detect changes to the current record in a recordset. Topics covered include:

  • Double buffering: definition

  • Using double buffering

  • Effects of double buffering

In the DAO database classes, records are double buffered by default. For information about turning double buffering off, see Using Double Buffering.

Double Buffering: Definition

In MFC's CDaoRecordset class, double buffering is a mechanism that simplifies detecting when the current record in a recordset has changed. Using double buffering with your DAO recordsets reduces the amount of work you have to do when adding new records and editing existing records.

By default, your MFC DAO recordsets keep a second copy of the edit buffer (the field data members of the recordset class, taken collectively; DAO Help calls the corresponding buffer a copy buffer). As you make changes to the data members, MFC compares them to the copy (the double buffer) to detect the changes.

Note Not all fields are double buffered by default. Variable length fields, such as those containing binary data, are not. But you can choose to double buffer them if you wish. Note that this can affect performance if the binary data is large.

The alternative to double buffering — not keeping a copy of the data — requires you to make additional function calls when you edit a field of the current record.

For example, suppose your user changes the name of her contact person at company X. With double buffering, MFC detects the change for you. Without it, you must accompany the change with a call to CDaoRecordset::SetFieldDirty and a call to SetFieldNull (with a parameter of FALSE). If a field is supposed to be Null, you must explicitly call SetFieldNull. You must make these calls for every change to a record field.

In general, you get better performance with double buffering off, but double buffering is a considerable convenience when performance is not critical.

Using Double Buffering

Double buffering is the default for recordset fields of most data types, but not for the variable-length data types, such as text and binary. Because data of those types is potentially very large, storing a second copy of the data is not a good default. However, if you know your data will not be prohibitively large, you can turn double buffering on for these types as well. You can also choose to turn double buffering off. You can control double buffering for the whole recordset or on a field-by-field basis.

Overall double buffering is controlled by the CDaoRecordset::m_bCheckCacheForDirtyFields data member. Field-by-field double buffering is controlled by the dwBindOptions parameter to any of the DFX functions (DFX_Text, DFX_Binary, DFX_Short, and so on).

To turn double buffering on or off for the whole recordset

  • Set the value of m_bCheckCacheForDirtyFields to AFX_DAO_ENABLE_FIELD_CACHE (on) or AFX_DAO_DISABLE_FIELD_CACHE (off). A typical place to do this is in the recordset constructor.

Note If this data member is TRUE (the default), double buffering is on for all field data members except those of variable-length data type (binary, long binary, and text). If this data member is FALSE, double buffering is off for all fields, regardless of data type.

To turn double buffering on or off for a specific field in the recordset

  • In the DFX function call for the field, set the dwBindOptions parameter to TRUE (on) or FALSE (off).

DFX function calls are made in your recordset class's DoFieldExchange member function. See the article DAO Record Field Exchange: Working with the Wizard Code for a discussion of DoFieldExchange.

Possible values for dwBindOptions are:

  • AFX_DAO_ENABLE_FIELD_CACHE (Default) Double buffering is on for the field.

  • AFX_DAO_DISABLE_FIELD_CACHE Double buffering is off for the field.

In the following example, double buffering is on for the first field but explicitly turned off for the second field.

void CSections::DoFieldExchange(CDaoFieldExchange* pFX)
{
    //{{AFX_FIELD_MAP(CSections)
    pFX->SetFieldType(CDaoFieldExchange::outputColumn);
    DFX_Short(pFX, "Capacity", m_Capacity);
    DFX_Short(pFX, "Enrollment", m_Enrollment,
                         AFX_DAO_DISABLE_FIELD_CACHE);
    //}}AFX_FIELD_MAP
}

Effects of Double Buffering

If double buffering is on, as it is by default, record data is double buffered when:

  • You call CDaoRecordset::Edit to edit the fields of the current record.

  • You call CDaoRecordset::AddNew to add a new record to the recordset.

MFC copies the field data members of the recordset into a buffer (the double buffer). Then it uses the copy to detect changes to the original field data members in the recordset. For more discussion of how double buffering fits into the record updating process, see the article DAO Record Field Exchange: How DFX Works.

Tip To improve performance you might sometimes prefer to turn double buffering off. However, alternatives include:

  • Creating queries that only return the fields and rows that you actually need.

  • Specifying in your recordset only the fields that you will always use. Then you can supplement those fields by calling CDaoRecordset::GetFieldValue at appropriate times to retrieve the fields you need only occasionally. See the article DAO Recordset: Binding Records Dynamically.

In the Class Library Reference, see CDaoRecordset::m_bCheckCacheForDirtyFields.

See Also DAO: Where Is..., DAO Recordset, DAO Record Field Exchange (DFX), DAO Record Field Exchange: Working with the Wizard Code


DAO Recordset

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes the key features of the MFC CDaoRecordset class. Additional articles explain how to use recordsets. For task-oriented information, see the article DAO Recordset: Creating Recordsets. For an understanding of the DAO recordset object underlying each MFC CDaoRecordset object, see the topic "Recordset Object" in DAO Help.

Topics covered include:

  • DAO recordset: definition

  • DAO recordset types

  • Derived DAO recordset classes

  • DAO recordset operations

  • Recordsets and querydefs

  • Recordsets and tabledefs

  • Recordsets and DAO collections

  • DAO recordset performance features

  • Further reading about DAO recordsets

DAO Recordset: Definition

A DAO recordset, represented in MFC by a CDaoRecordset object, represents the records in a base table or the records that result from running a query. Recordsets are the principal way in which you work with data using the MFC DAO classes. For a description of the DAO recordset object underlying each CDaoRecordset object, see the topic "Recordset Object" in DAO Help.

A recordset represents, simultaneously:

  • All of the records in a table or query — a set of records.

  • The current record in that set, whose fields fill the recordset's field data members, if any. Scrolling to a different record in the set fills the recordset's field data members with new values.

For information about recordset features and capabilities, including searching, navigating, updating, bookmarking, and constraining which records are selected, see class CDaoRecordset in the Class Library Reference. Also see the list of additional recordset articles in Further Reading About DAO Recordsets.

DAO Recordset Types

You can create three kinds of CDaoRecordset objects:

  • Table-type recordsets, representing a base table in a Microsoft Jet (.MDB) database

  • Dynaset-type recordsets, which result from a query

  • Snapshot-type recordsets, consisting of a static copy of a set of records

The following table summarizes the characteristics and purposes of the three recordset types.

Characteristics of Recordset Types

Characteristic | Table-Type | Dynaset-Type | Snapshot-Type
Based On | A base table | A query | A query
Updatable | Yes | Yes | No
Dynamic | Yes | Yes | No
Best Uses | Working with a single table (in a non-ODBC database). | Working with records, possibly containing fields from one or more tables. Reflects changes by other users and is updatable. | Finding data or preparing reports. Reflects the state of the data at the time of the snapshot.
Limitations | Can use only with .MDB databases or ISAM tables opened directly. | Doesn’t reflect new records that meet selection criteria after the recordset opens. See below. | Not updatable. The snapshot is not quite instantaneous. See below.

A table-type recordset is based directly on the table rather than on a query.

A dynaset is a recordset that reflects changes to the underlying records by other users of the database or by other recordsets. As your application scrolls to a changed record, a new copy is retrieved, bringing it up to date. This behavior is ideal for situations in which it is important to be completely up to date.

Note A dynaset is a dynamic but fixed set of records. New records that meet the selection criteria after the dynaset-type recordset has been created are not added to the recordset. This includes records that other users add.

A snapshot reflects the state of the data at a particular moment, the moment the snapshot is taken. This behavior is ideal for reporting.

Note Because it takes time to retrieve the records for a snapshot, the moment at which the snapshot occurs is not instantaneous.

Derived DAO Recordset Classes

Normally, you work with recordsets by deriving your own application-specific recordset classes from CDaoRecordset. You can create your recordset classes with AppWizard or ClassWizard (or by writing the same code yourself). When you use AppWizard or ClassWizard, the wizard prompts you to specify a database, a recordset type, and a table name on which to base the recordset. The wizard then lets you specify which columns to use in the recordset.

Recordset Features

The resulting recordset class has the following features:

  • It contains a data member for each column (field) in the recordset.

  • It has a member function you can use to get the name of the data source on which the recordset is based.

  • It has a member function you can use to get the SQL string on which the recordset query is based. You indirectly define the SQL string with ClassWizard. The string might contain a table name (for a table-type recordset that selects all fields in each record) or an SQL SELECT statement.

  • It has a member function, DoFieldExchange, that manages exchanging data between the data source and the recordset's data members (in both directions).

For more information about these features, see the article DAO Recordset: Architecture.

Binding Records Dynamically

You do not necessarily have to derive a recordset class. You can use CDaoRecordset objects directly, employing the GetFieldValue member function to retrieve individual columns (fields) of the current record immediately. For more information, see DAO Recordset: Binding Records Dynamically.

For information about using recordsets, see the article DAO Recordset: Creating Recordsets.

Recordsets and Querydefs

Besides constructing CDaoRecordset-based objects directly, you can create them indirectly from a CDaoQueryDef object. A querydef is a predefined query usually saved in a DAO database object's QueryDefs collection. Querydefs are a way to prepare frequently used or complex queries and store them in a database for reuse. One version of the CDaoRecordset::Open member function is initialized by a pointer to a CDaoQueryDef object.

Tip For convenience, you can use Microsoft Access to create querydefs. Then you can use the querydefs in your MFC program.

For more information, see the articles DAO Recordset: Creating Recordsets and DAO Querydef.

Recordsets and Tabledefs

As with querydefs, you can construct a recordset from a CDaoTableDef object. A tabledef encapsulates the structure definition of a table. Tabledefs are saved in the database object’s TableDefs collection. A version of CDaoRecordset::Open is initialized by a pointer to a CDaoTableDef object.

Tip For convenience, you can use Microsoft Access to create tabledefs. Then you can use the tabledefs in your MFC program.

For more information, see the articles DAO Recordset: Creating Recordsets and DAO Tabledef.

Recordsets and DAO Collections

DAO maintains a Recordsets collection, and each recordset maintains collections of DAO field objects and Index objects.

The Recordsets Collection

In DAO, the DAO database object maintains a Recordsets collection containing all active recordsets based on the database. When you open a DAO recordset it is appended to the collection.

MFC chooses not to expose the DAO Recordsets collection. In MFC, you have an explicit CDaoRecordset object in your program for each DAO recordset you create. It's up to you to keep track of the recordsets you open.

The Fields and Indexes Collections

In DAO, a recordset object maintains a collection of the fields in the recordset and a collection of the indexes in the underlying table.

MFC exposes each of these collections via member functions that let you get the number of objects in the collection and examine information about any of the objects. For more information about the GetFieldCount, GetFieldInfo, GetIndexCount, and GetIndexInfo member functions of CDaoRecordset, see the articles DAO Collections: Obtaining Information About DAO Objects and DAO Collections.

DAO Recordset Performance Features

In MFC, you can:

  • Cache multiple records from an ODBC data source in a configurable buffer.

    It takes longer to fill the buffer, but having multiple records in memory speeds searching and navigating in the recordset. Caching has no effect or benefit for non-ODBC data sources. For more information, see the article DAO Recordset: Caching Multiple Records.

  • Use a double-buffering mechanism in which two copies are kept of the current record. The second copy is used to test whether fields in the first copy have changed.

    Double buffering saves you the work of calling member functions such as SetFieldDirty or SetFieldNull for a field being edited. The trade-off is storing two copies, which can be a significant amount of memory for variable-length data types. For more information, see the article DAO Record Field Exchange: Double Buffering Records.

Further Reading About DAO Recordsets

For more information about recordsets, see the following articles. If you're new to recordsets, you might want to read the articles in the order listed.

Basic Recordset Operations

  • DAO Recordset: Creating Recordsets

  • DAO Queries

  • DAO Queries: Filtering and Parameterizing Queries

  • DAO Recordset: Recordset Operations

  • DAO Workspace: Managing Transactions

  • DAO Record Field Exchange (DFX)

Navigating in Recordsets

  • DAO Recordset: Recordset Navigation

  • DAO Recordset: Bookmarks and Record Positions

  • DAO Recordset: Seeking and Finding

Advanced Recordset Operations

  • DAO Recordset: Caching Multiple Records for Performance

  • DAO Recordset: Binding Records Dynamically

  • DAO Record Field Exchange: Double Buffering Records

  • DAO Tabledef: Examining a Database Schema at Run Time

  • DAO Recordset: Using Aggregate SQL Functions with MFC DAO Classes

See Also DAO: Where Is..., DAO Querydef, DAO Tabledef, DAO Workspace


DAO Recordset: Architecture

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC DAO classes. For ODBC recordsets, see the article Recordset: Architecture (ODBC).

This article describes the data members that make up the architecture of a recordset object:

  • Field data members

  • Parameter data members

  • m_nFields and m_nParams data members

A Sample DAO Recordset Class

When you use ClassWizard to declare a recordset class derived from CDaoRecordset, the resulting class has the general structure shown in the following simple class:

class CCourseSet : public CDaoRecordset
{
public:
  CCourseSet(CDaoDatabase* pDatabase = NULL);
  DECLARE_DYNAMIC(CCourseSet)

// Field/Param Data
  //{{AFX_FIELD(CCourseSet, CDaoRecordset)
  CString m_CourseID;
  CString m_CourseTitle;
  //}}AFX_FIELD
  CString m_IDParam;

// Overrides
  // ClassWizard generated virtual function overrides
  //{{AFX_VIRTUAL(CCourseSet)
  public:
  virtual CString GetDefaultDBName( );
  virtual CString GetDefaultSQL( );
  virtual void DoFieldExchange(CDaoFieldExchange* pFX);
  //}}AFX_VIRTUAL

// Implementation
// ...

};

Near the beginning of the class, ClassWizard writes a set of field data members inside the //{{AFX_FIELD delimiters. When you create the class with ClassWizard, you must specify one or more field data members. If the class is parameterized, as the sample class is (with the data member m_strIDParam), you must manually add parameter data members. ClassWizard doesn’t support adding parameters to a class.

DAO Field Data Members

The most important members of your recordset class are the field data members. For each column you select from the data source, the class contains a data member of the appropriate data type for that column. For example, the sample class shown at the beginning of this article has two field data members, both of type CString, called m_CourseID and m_CourseTitle.

When the recordset selects a set of records, the framework automatically binds the columns of the current record (after the Open call, the first record is current) to the field data members of the object. That is, the framework uses the appropriate field data member as a buffer in which to store the contents of a record column (field).

As the user scrolls to a new record, the framework uses the field data members to represent the current record. The framework refreshes the field data members, replacing the previous record’s values. The field data members are also used for updating the current record and for adding new records. As part of the process of updating a record, you specify the update values by assigning values directly to the appropriate field data member(s).

DAO Parameter Data Members

If the class is parameterized, it has one or more parameter data members. A parameterized class lets you base a recordset query on information obtained or calculated at run time. (For an alternative approach to parameterizing a recordset by using a querydef, see the article DAO Queries: Filtering and Parameterizing Queries.)

Note You must manually place these data members outside the //{{AFX_FIELD comment brackets.

Typically, the parameter helps narrow the selection, as in the following example. Based on the sample class at the beginning of this article, the recordset object might execute the following SQL statement:

SELECT CourseID, CourseTitle FROM Course WHERE CourseID = [Course Ident]

The [Course Ident] is a named parameter whose value you supply at run time. When you construct the recordset and set its m_strIDParam data member to “MATH101”, the effective SQL statement for the recordset becomes:

SELECT CourseID, CourseTitle FROM Course WHERE CourseID = MATH101

Note This is the effective SQL, but the actual SQL works more efficiently. In particular, it does not do a simple text replacement.

The square brackets are only required if the column or parameter name contains spaces.

By defining parameter data members, you tell the framework about parameters in the SQL string. The framework binds the parameter, which lets DAO know where to get values to substitute for the parameter name. In the example, the resulting recordset contains only the record from the Course table with a CourseID column whose value is “MATH101”. All specified columns of this record are selected. You can specify as many parameters (and named placeholders for them) as you need.

Note MFC does nothing itself with the parameters — in particular, it doesn’t perform a text substitution. Instead, MFC gives the parameter values to DAO, which uses them.

Important The name of a parameter is important. For details about this and more information about parameters, see the article DAO Queries: Filtering and Parameterizing Queries.

Using m_nFields and m_nParams with DAO

When ClassWizard writes a constructor for your class, it also initializes the m_nFields data member, which specifies the number of field data members in the class. If you add any parameters to your class, you must also add an initialization for the m_nParams data member, which specifies the number of parameter data members. The framework uses these values to work with the data members.

For more information and examples, see the articles DAO Record Field Exchange (DFX) and DAO Queries: Filtering and Parameterizing Queries. For related information, see the following topics in DAO Help:

  • Creating Parameter Queries with DAO

  • PARAMETERS Declaration (SQL)

See Also DAO: Where Is..., DAO Recordset, DAO Queries, DAO Querydef


DAO Recordset: Creating Recordsets

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the process of creating recordset objects based either on class CDaoRecordset itself or on a class derived from CDaoRecordset.

You can use recordset objects in two ways:

  • Create recordsets directly from class CDaoRecordset and bind record fields dynamically.

    For information about why and how to bind records dynamically, see the article DAO Recordset: Binding Records Dynamically.

  • Use AppWizard or ClassWizard to derive your own custom recordset class from CDaoRecordset and use DAO Record Field Exchange (DFX) to manage binding record data to recordset class field data members.

    For information about deriving recordset classes with the wizards, see the articles Overview: Creating a Program That Supports a Database and ClassWizard: Creating a Recordset Class.

    For information about using DFX, see the article DAO Record Field Exchange (DFX).

In either case, you can base your recordset objects on a query defined by a CDaoQueryDef object or a CDaoTableDef object, or you can specify the recordset objects’ SQL strings either at design time, when you create the class with a wizard, or at run time, when you pass a string containing an SQL statement to the CDaoRecordset::Open member function.

The following table describes the characteristics of a recordset, depending on how you create it:

If you base your recordset on... | It has these characteristics...
A querydef | The recordset inherits the querydef’s SQL string.
A tabledef | The recordset (a table-type recordset) is based on the table. Creating a recordset from a tabledef is similar to creating one from a querydef. See the following procedure for creating from a querydef.
The SQL string specified at design time, in the wizard | The recordset uses the SQL string retrieved by calling its GetDefaultSQL member function. The wizard codes the string as the value returned by this function.
An SQL string specified at run time, in the Open call | The SQL string passed to Open overrides the SQL defined at design time.

The following procedure shows how to use a querydef as the basis for a recordset. Using a tabledef to create a recordset is similar.

To create a recordset from a querydef

  1. Create the querydef, as described in Creating a Query with a Querydef, or use an existing querydef object.

  2. Construct a CDaoRecordset object.

  3. Call the recordset object's Open member function, passing a pointer to the querydef object.

Opening the recordset runs the query, using the SQL statement defined by the querydef.

Note You can only create a dynaset-type or snapshot-type recordset from a querydef.

The following code shows the process of creating a recordset from a querydef:

// pdb is a pointer to an open CDaoDatabase object
try
{
    // Construct the querydef
    CDaoQueryDef qd( pdb );

    // Set up the SQL string and create the querydef
    CString strSQL =
      _T(“SELECT [Company Name] FROM Publishers WHERE State = ‘NY’”);
    qd.Create( _T(“My Querydef”), strSQL );

    // Construct a CDaoRecordset-derived object
    // and open it based on the querydef
    CPublisherSet rsPub( pdb );
    rsPub.Open( &qd );
}
catch( CDaoException* e )
// ...

To create a recordset without a querydef

  1. Construct a CDaoRecordset object.

  2. Call the recordset object's Open member function. Specify an SQL string, or rely on the one that the wizard creates.

For an example in code, see the article DAO Recordset: Creating Recordsets.

The SQL statement for the recordset is one of the following:

  • The default SQL string that you established when you created the recordset class using AppWizard or ClassWizard. If you pass NULL for the lpszSQL parameter to Open, the recordset uses the default SQL string. The recordset obtains the default SQL string by calling its own GetDefaultSQL member function. The default SQL string is coded as the value returned by that function rather than being stored in a data member.

  • An SQL string that you pass in your call to Open. This string overrides the default SQL string defined in the recordset class.

In either case, your SQL string can consist of any of the following:

  • A SELECT statement of the basic form:
    SELECT column-list FROM table-list
  • One or more tabledef and/or querydef names, separated by commas, which base the query on tables and/or queries. This list is usually based on choices you made with one of the wizards. The query selects all columns (fields) in the tables/queries, unless you modify it.

For details, see CDaoRecordset::Open. For related information, see the topic "Recordset Object" in DAO Help.

For information about SQL, see the topic "SQL Property" in DAO Help.

For information about the SQL syntax used by DAO, see the topic "Comparison of Microsoft Jet Database Engine SQL and ANSI SQL" in DAO Help.

See Also DAO: Where Is..., DAO Recordset, DAO Querydef, DAO Record Field Exchange (DFX), DAO Queries: SQL for DAO, DAO Queries


DAO Recordset: Recordset Navigation

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to move (scroll) from record to record in a recordset. It also tells you where to find more information about other recordset navigation mechanisms, such as Seek, Find, and bookmarks.

Topics covered include:

  • Scrolling in DAO recordsets

  • Other navigation techniques

For more information, see the topic "Positioning the Current Record Pointer with DAO" in DAO Help.

Scrolling in DAO Recordsets

Recordsets provide several member functions you can use to scroll or move from one record to the next, previous, first, or last record, or move n records relative to the current position. You can also test whether you have scrolled beyond the first or the last record.

To determine whether scrolling is possible in your recordset, call the CanScroll member function of class CDaoRecordset.

To scroll in DAO

  • Forward one record: call the MoveNext member function.

  • Backward one record: call the MovePrev member function.

  • To the first record in the recordset: call the MoveFirst member function.

  • To the last record in the recordset: call the MoveLast member function.

  • N records relative to the current position: call the Move member function. Specify the value of N, negative (for previous records) or positive (for later records), in your call.

To test for the end or the beginning of the recordset in DAO

  • Have you scrolled past the last record? Call the IsEOF member function.

  • Have you scrolled past the first record (moving backward)? Call the IsBOF member function.

For example, the following code uses IsBOF and IsEOF to detect the limits of a recordset as the code scrolls through it in both directions.

// Open a snapshot; first record is current
CEnrollmentSet rsEnrollmentSet( NULL );
rsEnrollmentSet.Open( );

// Deal with empty recordset
if( rsEnrollmentSet.IsEOF( ) )
    return FALSE;

// Scroll to the end of the snapshot
while ( !rsEnrollmentSet.IsEOF( ) )
    rsEnrollmentSet.MoveNext( );

// Past last record, so no record is current
// Move to the last record
rsEnrollmentSet.MoveLast( );

// Scroll to beginning of the snapshot
while( !rsEnrollmentSet.IsBOF( ) )
    rsEnrollmentSet.MovePrev( );

// Past first record, so no record is current
rsEnrollmentSet.MoveFirst( );
// First record (if any) is current again

IsEOF returns a nonzero value if the recordset is positioned past the last record. IsBOF returns a nonzero value if the recordset is positioned before the first record. In either case, there is no current record to operate on. If you call MovePrev when IsBOF is already true, or call MoveNext when IsEOF is already true, the framework throws a CDaoException.

Tip In the general case, where records may be deleted by you or by other users (other recordsets), check that both IsEOF and IsBOF return a nonzero value to detect an empty recordset.

Other Navigation Techniques

Besides scrolling, discussed in Scrolling in DAO Recordsets, class CDaoRecordset supplies five other ways to navigate to a particular record or to a particular place in a recordset, as shown in the following table.

Ways to Navigate in an MFC DAO Recordset

CDaoRecordset Member Function | For more information...
Seek | See Using Seek in the article DAO Recordset: Seeking and Finding
Find | See Using Find in the article DAO Recordset: Seeking and Finding
SetBookmark | See Bookmarks in MFC DAO in the article DAO Recordset: Bookmarks and Record Positions
SetPercentPosition | See Absolute and Percent Positions in MFC in the article DAO Recordset: Bookmarks and Record Positions
SetAbsolutePosition | See Absolute and Percent Positions in MFC in the article DAO Recordset: Bookmarks and Record Positions

See Also DAO: Where Is..., DAO Recordset, DAO Recordset: Seeking and Finding, DAO Recordset: Bookmarks and Record Positions


DAO Recordset: Recordset Operations

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article discusses several key recordset operations, particularly those involving updating records. Topics covered include:

  • Adding new records

  • Editing existing records

  • Deleting records

  • Requerying recordsets

For related information about using recordsets, see the following articles:

  • DAO Queries

  • DAO: Creating, Opening, and Closing DAO Objects

  • DAO Recordset: Creating Recordsets

  • DAO Recordset: Recordset Navigation

  • DAO Recordset: Bookmarks and Record Positions

  • DAO Recordset: Seeking and Finding

  • DAO Recordset: Binding Records Dynamically

  • DAO Recordset: Caching Multiple Records for Performance

  • DAO Record Field Exchange (DFX)

  • DAO Recordset: Using Aggregate SQL Functions with MFC DAO Classes

Important Your ability to update records requires that you have update permission for your database and that you have an updatable table-type or dynaset-type recordset. You can't update snapshot-type recordsets with the MFC DAO classes.

Adding New Records in DAO

For general information about adding records in DAO, see the following topics in DAO Help:

  • Populating Recordsets and Counting Records with DAO

  • AddNew Method

  • Update Method

For information about where the new record appears and other considerations, see CDaoRecordset::AddNew. For information about the role of double buffering, see the article DAO Record Field Exchange: How DFX Works.

To add a new record to a recordset

  1. Determine whether your recordset is updatable.

    Call the recordset's CanUpdate member function.

  2. Call the recordset's AddNew member function.

    The fields of the new recordset, represented by the recordset's edit buffer (the recordset’s data members), are initially all Null. AddNew prepares the MFC recordset's edit buffer, which DAO calls the copy buffer. For more information about the edit buffer with AddNew, see the article DAO Record Field Exchange: How DFX Works.

  3. Assign values to the new record's fields.

    If you're using a CDaoRecordset-derived class with DFX, assign values to the fields. If you have double buffering turned off, make the following two calls for each field you assign a value to:

    • SetFieldDirty

    • SetFieldNull with the parameter FALSE (meaning “not Null”).

    Or, if you explicitly want the field to be Null, call only SetFieldNull, with the parameter TRUE.

  4. Complete the process by calling the recordset's Update member function.

    Update adds the record. If no transaction is in effect, the change takes place immediately. Otherwise, the change takes place when you call CDaoWorkspace::CommitTrans.

If you move to another record without calling Update, the change is lost. For more information, see AddNew.

Editing Existing Records in DAO

For general information about editing records in DAO, see the following topics in DAO Help:

  • Edit Method

  • Update Method

If you have double buffering turned on, MFC maintains a copy of the edit buffer so it can detect changes to the recordset fields for you. You don't have to call SetFieldDirty and SetFieldNull (passing FALSE) for each change. For more information, see the article DAO Record Field Exchange: Double Buffering Records.

For details about what Edit does and about the role of double buffering, see CDaoRecordset::Edit and the article DAO Record Field Exchange: How DFX Works.

To edit an existing record in a recordset

  1. Determine whether your recordset is updatable.

    Call the recordset's CanUpdate member function.

  2. Move to the record you want to edit.

    Use any of the recordset's navigation mechanisms that take you to a specific record.

  3. Call the recordset's Edit member function.

    Edit prepares the recordset's edit buffer, which DAO calls the copy buffer. For more information about the edit buffer with Edit, see the article DAO Record Field Exchange: How DFX Works.

  4. Assign values to the fields you want to change.

    If you're using a CDaoRecordset-derived class with DFX, assign values to the fields. To give a field the value Null, call SetFieldNull (passing TRUE). If you have double buffering turned off, call SetFieldDirty and SetFieldNull (passing FALSE) for each field you assign a value to.

  5. Complete the process by calling the recordset's Update member function.

    Update changes the record in the database. If no transaction is in effect, the change takes place immediately. Otherwise, the change takes place when you call CDaoWorkspace::CommitTrans.

If you move to another record without calling Update, the change is lost. For more information, see Edit. For information about double buffering, see the article DAO Record Field Exchange: Double Buffering Records.

Deleting Records in DAO

For general information about deleting records in DAO, see the topic "Delete Method" in DAO Help.

To delete a record from a recordset

  1. Determine whether your recordset is updatable.

    Call the recordset's CanUpdate member function.

  2. Move to the record you want to edit.

    Use any of the recordset's navigation mechanisms that take you to a specific record.

  3. Call the recordset's Delete member function.

    You don't call Update for a deletion.

  4. Move to another record before you attempt any other recordset operations.

In table-type and dynaset-type recordset objects, Delete removes the current record and makes it inaccessible. Although you can't edit or use the deleted record, it remains current. Once you move to another record, however, you can’t make the deleted record current again. Subsequent references to a deleted record in a recordset are invalid and cause an exception to be thrown. For more information, see Delete. You can tell whether you’re on a deleted record by calling IsDeleted.

Requerying in DAO

If you need to re-run a recordset query, perhaps with new parameter values each time, you can do either of the following:

  • Call Close to close the recordset, reset any parameters or other properties, and call Open again.

  • Reset any parameters or other properties, then call Requery.

The purpose of either approach to requerying the recordset is to refresh the recordset by running its query again, perhaps with changed parameters or properties. You can also requery to refresh results in a multi-user environment (multiple users or recordsets modifying the same data). In general, Requery is somewhat more efficient than Close and Open, but see the Important note below.

This description of the use and behavior of Requery is exactly as in DAO. But MFC adds one feature: your ability to change the recordset’s m_strFilter and/or m_strSort data members before you either call Requery or call Open again. If you do change either data member, MFC closes, then reopens the recordset.

Important If you change m_strFilter or m_strSort, you lose the performance benefit of Requery. In this case, calling Requery performs no better than calling Close and Open.

For more information, see Requery in the Class Library Reference, and see the topic "Requery Method" in DAO Help.

See Also DAO: Where Is..., DAO Recordset


DAO Recordset: Bookmarks and Record Positions

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains MFC's interfaces to:

  • The Bookmark property in DAO recordsets.

  • The AbsolutePosition and PercentPosition properties in DAO recordsets.

For details about these properties in DAO, see the following topics in DAO Help:

  • Bookmark Property

  • AbsolutePosition Property

  • PercentPosition Property

  • Positioning the Current Record Pointer with DAO

Those DAO Help topics explain the fundamentals of the properties. This article explains how MFC exposes them to you.

Bookmarks in MFC DAO

Because records can be deleted from a recordset, you can't rely on the absolute position of a record within the recordset. The reliable way to keep track of the position of a particular record in your recordset is to use the record's bookmark.

Except for snapshot-type recordsets, each record has a unique bookmark from the time the recordset is created. In MFC, class CDaoRecordset supplies member functions for:

  • Getting the bookmark of the current record, so you can save it in a variable.

  • Moving quickly to a given record by specifying its bookmark, which you've saved earlier in a variable.

You can check whether a recordset supports bookmarks by calling CDaoRecordset::CanBookmark.

For example, suppose you want to mark the current record so you can later return to it easily. The following code does this:

// rs is a CDaoRecordset or
// CDaoRecordset-derived object

COleVariant varRecordToReturnTo;
varRecordToReturnTo = rs.GetBookmark( );

//...more code in which you move to other records
rs.SetBookMark( varRecordToReturnTo );

There is no need to extract the underlying data type from the COleVariant object. Simply get it with CDaoRecordset::GetBookmark and return to that bookmark with CDaoRecordset::SetBookmark.

Absolute and Percent Positions in MFC DAO

Besides bookmarks (and Move, Seek, and Find), DAO provides two other ways to position the current record in a recordset: percent positioning and absolute positioning.

Note Neither absolute nor percent positioning is recommended for moving the current record to a specific record. Use a bookmark instead. See DAO Recordset: Bookmarks and Record Positions.

Neither percent positioning nor absolute positioning is available for table-type recordsets.

Percent Positioning

You can set the current record to a position that follows a specified percentage of the records in a recordset, and you can get the percentage position of the current record. This is useful for setting scroll bars. That is, you can:

  • Call CDaoRecordset::GetPercentPosition to determine the percentage position of the current record, that is, what percentage of the records precede the current record.

  • Call CDaoRecordset::SetPercentPosition to make the record at a specified percentage position in a recordset the current record. For example, you might make the record at 50% of the current record, halfway through the recordset.

Keep in mind the following guidelines:

  • Percent positioning is approximate, and the exact record that is set can be affected by deletion of records.

  • If you call SetPercentPosition before the recordset is fully populated, the amount of movement is relative to the number of populated records. Records are populated as you move to them and they are retrieved from the database. You can determine the number of populated records by calling GetRecordCount. You can populate all records in the recordset by calling MoveLast (keep in mind that calling MoveLast can be slow for dynaset-type and snapshot-type recordsets).

For related information, see the topic "PercentPosition Property" in DAO Help.

Absolute Positioning

You can set or get the record number of the current record in a recordset. That is, you can:

  • Call CDaoRecordset::GetAbsolutePosition to get the AbsolutePosition property of the recordset, which contains the ordinal position (zero-based) of the current record in a recordset.

  • Call CDaoRecordset::SetAbsolutePosition to set the AbsolutePosition property. This makes the record at that ordinal position in the recordset the current record.

Important The absolute position of a record is potentially unreliable. If the user can delete records ahead of a position, the ordinal number of records following the deletion is decreased. Bookmarks are a more reliable method of working with record positions. See Bookmarks in MFC DAO.

Keep in mind the following guideline:

  • Setting a position greater than the number of populated records causes MFC to throw an exception. Records are populated as you move to them and they are retrieved from the database. You can determine the number of populated records by calling GetRecordCount.

For related information, see the topic "AbsolutePosition Property" in DAO Help.

See Also DAO: Where Is..., DAO Recordset, DAO Recordset: Recordset Navigation, DAO Recordset: Seeking and Finding


DAO Recordset: Seeking and Finding

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to use the Seek and Find member functions of class CDaoRecordset. Topics covered include:

  • Using Seek

  • Using Find

These two mechanisms for locating records that meet certain criteria are used in different situations, as described in the following table.

Using Seek vs. Using Find

Criterion | Seek | Find
Use In | Indexed table-type recordsets. | Dynaset-type or snapshot-type recordsets.
Limitations | Can't use on attached tables, but can use on installable ISAM databases. | Can't use on a forward-only scrolling snapshot-type recordset. Use with ODBC-based recordsets can be inefficient.
Call Before Seek/Find | SetCurrentIndex |
Call After Seek/Find | Check Seek or Find return value | Check Seek or Find return value

Seek and Find are not the only means of navigating in a recordset. You can also use:

  • Move, MoveFirst, MoveLast, MoveNext, and MovePrev

  • GetBookmark, SetBookmark

  • GetAbsolutePosition, SetAbsolutePosition

  • GetPercentPosition, SetPercentPosition

For more information, see each CDaoRecordset member function in the Class Library Reference.

Using Seek

The CDaoRecordset::Seek member function lets you search for a record in a table-type recordset based on a table index. Two versions of the function provide for seeking based on:

  • Up to three specified keys, each of which represents a field that makes up part of the current index.

  • An array of keys, for indexes with four or more fields. Each key represents one of the fields. The array must contain at least one and no more than 13 keys.

In both versions, the search is based on a string containing a relational operator, such as "=" or ">=", in the lpszComparison parameter and the COleVariant value specified in the first key.

For example, suppose the comparison operator is "=" and the first key is the value "Microsoft" (the first key being a Company Name field). Using the first version of Seek, you would find the first record that has a Company Name of "Microsoft". The found record becomes the current record. The following code illustrates how to use Seek:

// rs is a table-type recordset
try
{
    // Set current index for recordset and
    // save current position.
    rs.SetCurrentIndex( _T("PartNameIndex") );
    COleVariant varCurrentPos = rs.GetBookmark( );

    // variant used as a key in Seek
    COleVariant varKey (_T("Framis Lever"), VT_BSTRT);

    // Find first record whose Part Name
    // field is "Framis Lever".
    if ( rs.Seek( _T("="), &varKey ) )
        // Return to the saved position
        rs.SetBookmark( varCurrentPos );
    else
        // Do something in response to Seek failure
}
catch( CDaoException* e )
{
    e->Delete( );
}

This code seeks the first record whose Part Name field (the first field in the PartNameIndex index) is "Framis Lever" (whatever a framis lever is).

For more information, see the Seek and SetCurrentIndex member functions in the Class Library Reference. For related information about the underlying DAO functionality, see the following topics in DAO Help:

  • Seek Method

  • NoMatch Property

  • Index Object

  • Index Property

Using Find

The CDaoRecordset::Find member function and its relatives, FindNext, FindPrev, FindFirst, and FindLast, let you search for a record in a dynaset-type or snapshot-type recordset. The Find member functions search from a location and in a direction as shown in the following table.

The Find Family of Functions

Find operation | Begin at | Search direction
FindFirst | Beginning of recordset | End of recordset
FindLast | End of recordset | Beginning of recordset
FindNext | Current record | End of recordset
FindPrev | Current record | Beginning of recordset

The basic Find function takes two parameters:

  • The type of find: AFX_DAO_NEXT, AFX_DAO_PREV, AFX_DAO_FIRST, or AFX_DAO_LAST.

  • A filter — a string expression like the WHERE clause in an SQL statement (without the keyword), that specifies the criterion for finding. The expression can be compound, using AND, OR, and so on.

Find is a virtual function. This means you can, if necessary, override it to provide your own implementation. The other Find functions are all based on Find, so they use whatever functionality you provide in your override. You shouldn't normally need to override Find, however.

For details not discussed here about the Find member functions, see the individual functions, starting with Find. For related information about the underlying DAO functionality, see the topic "Positioning the Current Record Pointer with DAO" in DAO Help:

For example, suppose you have a dynaset-type recordset in which you want to find the first record with a State code of "NY":

// rs is a dynaset-type recordset previously opened
CString strCriteria = _T("STATE = ‘NY’");
try
{
    if ( rs.FindFirst( strCriteria ) )
       // Do something with the found record
    rs.FindNext( strCriteria );
    // ...
}
catch( CDaoException* e )
{
    e->Delete( );
}

This code finds the first record that matches the criterion, then finds the next record that matches the criterion.

See Also DAO: Where Is..., DAO Recordset, DAO Recordset: Recordset Navigation, DAO Recordset: Bookmarks and Record Positions


DAO Recordset: Binding Records Dynamically

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to use an object of class CDaoRecordset directly, without deriving your own recordset class. Topics covered include:

  • The Standard Case: Using a Derived Recordset Class

  • Binding records dynamically instead

  • Dynamically setting and getting parameter values

As the MFC Database sample DAOVIEW shows, you can use dynamic binding to work with database schema information not known at design time. For related information on examining a database schema at run time, see the article DAO Tabledef: Examining a Database Schema at Run Time.

The Standard Case: Using a Derived Recordset Class

For many applications, you will prefer to create, at design time, a CDaoRecordset-derived class. Using AppWizard or ClassWizard, you can design a class that represents your table or query. You specify the database, the table, and the columns (fields). This information is then encapsulated in the class's connection information, its SQL string, and its data members. Records are statically bound to the recordset at run time via the DoFieldExchange mechanism. For more information, see the article DAO Recordset: Creating Recordsets.

The point is that to operate this way, you must know the database schema at design time so you can specify which table to use and which fields to use from that table. In many applications, this works well. If your database schema is relatively static and users are not constantly adding or deleting tables and table fields, you can design in this way.

Binding Records Dynamically Instead

If your database schema is relatively dynamic, or if you face a situation in which the schema is unknown at design time, dynamic binding could be the answer.

For dynamic binding, you don't need a derived CDaoRecordset class. Instead, you use CDaoRecordset directly. Here's the general process:

  1. Construct a CDaoRecordset object.

  2. Call its Open member function to connect to a specified database and run a query.

  3. Navigate through the records, using the recordset's navigation member functions, such as Move.

  4. Call the recordset's GetFieldValue member function to retrieve, immediately, the value of a specified field in the record. Or call Edit, then SetFieldValue, then Update to set the field in the database.

Binding dynamically in this way is flexible. You don't have to know the database schema at design time, and you can keep up with a changing schema. This mechanism doesn't use the DoFieldExchange mechanism.

You may get better performance with dynamic binding than with static binding via DAO record field exchange (DFX) if you don’t need every field bound for every record retrieved. However, for applications in which the database schema is reasonably unchanging, binding via DFX is a good choice because DFX manages all of the recordset’s fields for you, reducing the amount of code you must write to bind fields.

The following example, borrowed from the MFC Database sample DAOVIEW, illustrates dynamic binding. The code creates a table-type recordset, which is used to scroll through all records in a table, getting the values of fields in the current record and adding them to an MFC CListCtrl object.

Note For more information on the CCrack or CListCtrlEx classes used in the following example, see the MFC Database sample DAOVIEW.

// db is a pointer to a CDaoDatabase object.
// dbOpenTable specifies a table-type recordset.
// CCrack is a custom class used to get the actual
// type from a COleVariant object.
// nRecord is used for positioning in the list control.
 // the list control used here is an extended version
 // implemented in DAOView.  The CListCtrl class does not
 // provide an AddItem() member function as does the
 // extended version.
// m_ctlList is a CListCtrlEx object; this class
// implements an AddItem method for the list control.

CDaoRecordset rs( &db );
int nRecord = 0;

// Open MFC DAO objects in a try block to catch
// security violations when opening tables
try
{
    // Open the recordset, passing a table name
    // for the SQL
    rs.Open( dbOpenTable, strTableName );

    // Move through records
    while( !rs.IsEOF( ) )
    {
        COleVariant var;
        // Move through fields in current record
        int nFields = rs.GetFieldCount( );
        for ( int i=0; i < nFields; i++ )
        {
            var = rs.GetFieldValue( i );
            // Add field value to list control
            m_ctlList.AddItem( nRecord,i,
                              CCrack::strVARIANT( var ) );
        }
        nRecord++;
        rs.MoveNext( );
    }
}
catch( CDaoException* e )
{
    // Do nothing--used for security violations
    // when opening tables
    e->Delete( );
}

The key features in this example are:

  • The direct use of CDaoRecordset rather than a class derived from CDaoRecordset. The example therefore doesn’t use the DAO record field exchange (DFX) mechanism.

  • The call to GetFieldValue, which returns a value of type COleVariant for a specified field in the current record. The field is specified as the index of the field in the recordset object's Fields collection.

Also of interest are:

  • The user-defined class CCrack, which has members for extracting the actual data type from a COleVariant object. See the files CRACK.H and CRACK.CPP in the MFC Database sample DAOVIEW. CCrack is not an official MFC class.

  • The use of an exception handler around the CDaoRecordset::Open call and the other recordset operations. Using a try/catch block is recommended, if only to catch security violations when you try to open a table.

Note In addition to binding recordset fields dynamically, you can also bind query parameters dynamically. If you base your CDaoRecordset on a CDaoQueryDef object that has parameters defined, you can get or set the values of the parameters by calling CDaoQueryDef::GetParamValue or CDaoQueryDef::SetParamValue. Set parameter values for the querydef, then open a recordset based on the querydef. This mechanism doesn’t use DFX.

For other examples of dynamic binding, see the LISTVIEW.CPP file in the MFC Database sample DAOVIEW, and see the MFC Database sample DAOCTL, which illustrates a data-bound ActiveX control.

Dynamically Setting and Getting Parameter Values

If you create recordsets based on a querydef object, you can parameterize the querydef, then use it to create a recordset:

  1. Use the PARAMETERS clause in the querydef’s SQL statement to establish the parameters. For information, see the topics "PARAMETERS Declaration (SQL)" and "Creating Parameter Queries with DAO" in DAO Help. See also the article DAO Queries: Filtering and Parameterizing Queries.

  2. Create the querydef based on that SQL statement. See the article DAO Querydef: Using Querydefs.

  3. Set the values of the parameters by calling CDaoQueryDef::SetParamValue for each parameter.

  4. Create and open a recordset based on the querydef. See the article DAO Recordset: Creating Recordsets.

If you want to examine the value of a querydef’s parameter, call CDaoQueryDef::GetParamValue.

See Also DAO: Where Is..., DAO Recordset, DAO Tabledef: Examining a Database Schema at Run Time


DAO Recordset: Caching Multiple Records for Performance

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article discusses the mechanism by which you can use a configurable buffer to cache multiple records in a recordset.

Note The recordset caching mechanism described here applies only to ODBC data sources. It has no effect or benefit with non-ODBC databases.

Topics covered include:

  • When should you use record caching?

  • Configuring the record cache

  • Filling the record cache

Normally, records are retrieved from the database one at a time. To improve the performance of operations such as seeking and scrolling in recordsets based on ODBC data sources, you can cause DAO to cache multiple records. When you request a record, the database engine looks for it first in the cache. If the record is not in the cache, the database engine gets the record from the server. This is marginally slower at the time the cache is filled, but faster for operations that navigate through the records later. Use of this mechanism is limited in several ways, however (besides its limitation to ODBC); see When Should You Use Record Caching?.

For an understanding of the DAO data caching mechanism that underlies MFC CDaoRecordset objects, see the following topics in DAO Help:

  • CacheSize, CacheStart Properties

  • FillCache Method

When Should You Use Record Caching?

Is record caching right for your application? This depends on several factors:

  • Are you using a remote data source? Caching is really useful only for remote data — ODBC data sources.

  • Are you using dynaset-type recordsets? Caching is for use with these recordsets only.

  • What kind of performance do you need to optimize? If your application makes intensive use of scrolling, seeking, finding, or other methods of positioning the current record, you probably should cache records.

  • Keep in mind that caching requires storage space and that it can take extra time to fill the cache. Records retrieved from the cache also don't reflect changes made by other users in the database.

Configuring the Record Cache

To use MFC's record caching, you need to do two things:

  • Set the record position at which the cache is to start.

    Specify the first of the records to be cached by giving its bookmark in a call to CDaoRecordset::SetCacheStart. You can obtain a record's bookmark by moving to the record and calling CDaoRecordset::GetBookmark. GetBookmark returns a COleVariant value that you can store in a variable. Use the variable in your SetCacheStart call.

  • Set the size of the cache, in records.

    Call CDaoRecordset::SetCacheSize to specify how many records are to be cached.

How big should you make your cache? This depends on your needs and what you are optimizing for. If you expect your users to perform long scrolls or seeks, moving through many records at a time, you probably need a larger cache.

A typical case might be an application that, for example, displays 25 records at a time. For such an application, a cache of 75 records might be a good choice. This would allow quick response for both scrolling up and down and paging up and down.

Filling the Record Cache

DAO fills the cache as you request that records be retrieved from the data source. But you can explicitly fill all or part of the cache at any time by calling CDaoRecordset::FillCache.

When you call FillCache, you can specify either or both of the following:

  • The bookmark of the record at which you want to start filling the cache. If you omit the lBookmark parameter to FillCache, the cache is filled starting with the record specified in DAO's CacheStart property. You can set that value with CDaoRecordset::SetCacheStart.

  • The number of records you want to put into the cache. This can be less than the cache size you specified with a call to CDaoRecordset::SetCacheSize. If you omit the lSize parameter to FillCache, the number of records defaults to DAO's CacheSize property value, which you can set with SetCacheSize.

For more information, see the CDaoRecordset::FillCache member function in the Class Library Reference. For information about the DAO caching mechanism, see the following topics in DAO Help:

  • CacheSize, CacheStart Properties

  • FillCache Method

See Also DAO: Where Is..., DAO Recordset


DAO Recordset: Using Aggregate SQL Functions with MFC DAO Classes

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

With DAO records, you can't use the techniques described in the article Recordset: Obtaining SUMs and Other Aggregate Results (ODBC), which works for the MFC ODBC classes only. However, there are two methods for retrieving information from aggregate SQL functions using the MFC DAO classes:

  • Use CDaoRecordset::GetFieldValue.

  • Modify a CDaoRecordset-derived class by:
    • Changing the SQL statement used.

    • Placing column alias names in DFX calls of the recordset's DoFieldExchange member function.

Retrieve SQL Values with CDaoRecordset::GetFieldValue

CDaoRecordset::GetFieldValue allows you to use a CDaoRecordset object without deriving a class from it. You can retrieve records from an SQL statement that contains an aggregate function with GetFieldValue.

For example, if you have a student database that contains the names of students and test scores for each, and you want the average score for each student (a kind of aggregate value), you can use the following code:

  CDaoDatabase db;
  db.Open(_T("d:\\scores.mdb"));

  CDaoRecordset rs(&db);
  rs.Open(dbOpenDynaset,
         _T("Select [Student Name], AVG([Test Score]) AS AvgScore FROM
                SCORES GROUP BY [Student Name]"));
  while (!rs.IsEOF())
  {
     COleVariant varName;
     COleVariant varAvg;
     varName= rs.GetFieldValue("student name");
     varAvg=  rs.GetFieldValue("AvgScore");
// We know the return values are BSTR and VT_R8 types.
// If we didn't know, we would have to look at the vt
// member of COleVariant to see what type the data is.

// Prints the data to output window of debugger.
     TRACE(_T("%s\n%f\n"), V_BSTRT(&varName), V_R8(&varAvg));
     rs.MoveNext();
  }
  rs.Close();
  db.Close();

Notice that the alias name AvgScore is used for the column that contains the average score for each student.

For more on DAO and SQL, see the article DAO Queries: SQL for DAO.

Using a CDaoRecordset-Derived Class to Retrieve SQL Values

You can use a CDaoRecordset-derived class to retrieve the results of an SQL statement with an aggregate SQL function, as follows:

  • Explicitly specify the full SQL statement as the second argument of the Open call or specify the full SQL statement in the GetDefaultSQL function. Then, in the SQL statement, specify a column alias for the functions that will contain the results of aggregate SQL functions such as AVG or SUM.

    For example (assuming you have defined a recordset rs):

      rs.Open(dbOpenDynaset,
        _T("Select [Student Name], AVG([Test Score]) AS AvgScore FROM
            SCORES GROUP BY [Student Name]"));
  • Modify the DFX functions in the DoFieldExchange function of the CDaoRecordset-derived class so that it uses the alias names. For more on the DFX functions, see Record Field Exchange Functions in the Class Library Reference.

    For example:

      void CMyRecordset::DoFieldExchange(CDaoFieldExchange* pFX)
  {
  ...
     DFX_Text(pFX, _T("[student name]"), m_student_name);
     DFX_Double(pFX, _T("[AvgScore]"), m_avg_score);
     ...
  }

With this technique, you do not need to work with COleVariant objects as you do when retrieving SQL values with CDaoRecordset::GetFieldValue.

After the recordset has been modified, here is what the code might look like:

  CAvgSet rs;
  rs.Open(dbOpenDynaset,
         _T("Select [Student Name], AVG([Test Score]) AS AvgScore
             FROM SCORES GROUP BY [Student Name]"));
  while (!rs.IsEOF())
  {
     TRACE(_T("%s\n%f\n"), (LPCSTR)rs.m_student_name,
           rs.m_test_score);
     rs.MoveNext();
  }
  rs.Close();

See Also DAO Queries: SQL for DAO, Recordset: Obtaining SUMs and Other Aggregate Results (ODBC)


DAO Tabledef

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes "tabledefs" and the key features of the MFC CDaoTableDef class. Additional articles explain how to use tabledefs. For task-oriented information, see the article DAO Tabledef: Using Tabledefs. For an understanding of the DAO tabledef object underlying each MFC CDaoTableDef object, see the topic "TableDef Object" in DAO Help.

Topics covered include:

  • Tabledef: definition

  • Tabledef uses

  • Tabledefs and DAO collections

  • Further reading about tabledefs

Tabledef: Definition

A DAO tabledef, represented in MFC by a CDaoTableDef object, is an object that defines the structure of a base table or an attached table.

A base table is a table in a Microsoft Jet (.MDB) database. You can manipulate the structure of a base table using DAO objects or data definition language (DDL) SQL statements, and you can use recordsets and action queries to modify data in a base table.

An attached table is a table in another database linked to a Microsoft Jet (.MDB) database. Data for attached tables remains in the external database where it may be manipulated by other applications. You can't use the table-type recordset with attached tables, and you can’t modify the schema of attached tables, but you can use dynaset-type and snapshot-type recordsets with attached tables.

Tabledef Uses

The main use for tabledef objects is to manipulate the structure of a table. You can:

  • Base a recordset on a tabledef. The recordset is a table-type recordset. See CDaoRecordset::Open in the Class Library Reference.

  • Examine the structure of local base tables, attached tables, and external tables. The structure of a table includes its fields and indexes.

  • Add or delete fields and indexes in local base tables and external tables that you open directly rather than attaching.

  • Set the connection information and the name of an attached table and refresh the link to an attached table.

  • Determine whether the data in table fields is editable.

  • Get or set a table's validation conditions.

You can use tables as the basis for opening recordsets in two ways. You can:

  • Open a recordset based on a CDaoTableDef pointer.

  • Create a table-type recordset based on the table, usually by using AppWizard or ClassWizard.

For a complete discussion of what you can do with tabledefs, see the topic "TableDef Object" in DAO Help.

Tabledefs and DAO Collections

Each DAO database object maintains a TableDefs collection — a collection of all saved table definitions in the database. The collection contains one tabledef for each table in the database. Each tabledef object maintains two collections of its own:

  • Fields All of the fields in the table definition — one for each field in the underlying table.

  • Indexes All of the indexes defined for the table.

MFC objects don't store a representation of a DAO collection. Instead, MFC accesses the collection through the underlying DAO object. For more information, see the article DAO Collections.

MFC also doesn't provide a C++ class to represent every DAO object. In particular, there is no MFC field object or index object. You work with a tabledef's fields and indexes through member functions of class CDaoTableDef.

Further Reading About Tabledefs

For more information about tabledefs in MFC, see the following additional articles (in the order listed here):

General Tabledef Article

  • DAO Tabledef: Using Tabledefs

  • DAO Tabledef: Examining a Database Schema at Run Time

Tables in External Data Sources

  • DAO External: Working with External Data Sources

  • DAO External: Attaching External Tables

  • DAO External: Opening External Databases Directly

  • DAO External: Creating an External Table

  • DAO External: Refreshing and Removing Links

  • DAO External: Improving Performance with External Data Sources

See Also DAO: Where Is..., DAO Querydef, DAO Recordset, DAO Database


DAO Tabledef: Using Tabledefs

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to use CDaoTableDef objects. Topics covered include:

  • Creating a tabledef

  • Opening an existing tabledef

  • Creating a table-type recordset

Creating a Tabledef

Creating a tabledef creates a new table in the target database. You create the tabledef and add fields (and possibly indexes) to it. The new table doesn't contain any data until you either add records from Microsoft Access (for a Microsoft Jet (.MDB) database) or create a recordset that adds records to the table.

Creating a new MFC CDaoTableDef object creates the underlying DAO tabledef object.

To create a tabledef

  1. Construct a CDaoTableDef object, supplying a pointer to the CDaoDatabase object to which the tabledef will belong.

  2. Call the tabledef object's Create member function.

  3. Set any of the tabledef object’s properties that you want. Call the SetAttributes, SetConnect, SetName, SetSourceTableName, SetValidationRule, or SetValidationText member functions.

  4. Add fields to the tabledef by calling its CreateField member function for each field. (You can’t modify the schema of an attached table, so this step applies only to local base tables and tables in external data sources that you open directly.)

  5. Optionally add indexes to the tabledef by calling its CreateIndex member function for each index.

  6. Call the tabledef object’s Append member function to save the tabledef in the database’s TableDefs collection.

Tip The easiest way to create a tabledef is to create it in Microsoft Access. Open the target database, create tables, and save them in the database. Then you can use the tabledefs from your application’s code.

Opening an Existing Tabledef

If you want to examine or manipulate the structure of an existing table, open an MFC tabledef object based on the DAO tabledef object stored in the database's TableDefs collection. Objects in the TableDefs collection are accessed by the user-defined name specified when the tabledef was created and appended to the collection.

To open a tabledef for an existing table

  1. Construct a CDaoTableDef object, passing a pointer to the CDaoDatabase object to which the tabledef belongs.

  2. Call the tabledef object's Open member function, specifying the user-defined name of the tabledef saved in the TableDefs collection. The name may or may not be the same as the name of the underlying source table.

For examples, see the MFC Database sample DAOVIEW.

The following code from the LISTVIEW.CPP file in DAOVIEW illustrates opening a tabledef to get information about its fields and then add the field information to a list control:

// db is an open CDaoDatabase object
// strTableName is the user-defined name of the tabledef to open
CDaoTableDef td( &db );
try
{
    td.Open( strTableName );
    short nFields = td.GetFieldCount( );
    for( short i=0; i < nFields; i++ )
    {
        td.GetFieldInfo(i,fieldInfo);
        m_ctlList.AddColumn(fieldInfo.m_strName,i);
    }
}
catch( CDaoException* e )
{
    // Do nothing. Used to catch security violations opening tables.
    e->Delete( );
}
td.Close( );

Creating a Table-Type Recordset

Unless a table is in an external data source, you can create table-type recordsets based on the table, in two ways:

  • Create a tabledef, then create a recordset from the tabledef.

  • Create a recordset and specify dbOpenTable in the nOpenType parameter to CDaoRecordset::Open.

A table-type recordset represents a base table (a table in a Microsoft Jet (.MDB) database) in code. You can’t open a table-type recordset on an ODBC database or on an attached table, but you can open one on an ISAM database opened directly, such as a FoxPro, dBASE or Paradox database.

You can use a table-type recordset to examine, add, change, or delete records in a single base table. You can’t use an SQL statement to filter or sort data as you can with dynaset-type and snapshot-type recordsets. This means you get all records, but table-type recordsets behave somewhat like dynaset-type recordsets in that only the current record is loaded into memory. When you move to a new record, it is loaded. Sorting is based on a predefined index. Table-type recordsets support bi-directional scrolling.

For more information, see class CDaoRecordset in the Class Library Reference and see the following topics in DAO Help:

  • Recordset Object

  • Table-Type Recordset Object

See Also DAO: Where Is..., DAO Recordset, DAO External: Working with External Data Sources, DAO External: Creating an External Table


DAO Tabledef: Examining a Database Schema at Run Time

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article discusses how to examine the schema of a database — the structure of the database, as defined by its tables and their fields and indexes — at run time. While many applications are based on knowledge of the database schema at design time, there are situations in which you might need to determine the schema dynamically at run time:

  • Your application is designed to work with arbitrary schemas.

    See the MFC Database sample DAOVIEW for an example of this.

  • The schema of your target database tends to change.

    Perhaps users can add and delete tables and even alter the structure of tables by adding or deleting fields and indexes.

How Dynamic Examination of the Schema Works

Dynamic examination of the schema is based on the use of DAO collections. A DAO database object contains the following collections: TableDefs, QueryDefs, Recordsets, and Relations. MFC exposes all of these via CDaoDatabase member functions except for the Recordsets collection. For details about how MFC exposes collections, see the articles DAO Collections and DAO Collections: Obtaining Information About DAO Objects.

An Example of Dynamic Schema Examination

The following illustration uses the TableDefs collection, but the principles demonstrated apply equally to the other collections.

To enumerate the TableDefs collection for a CDaoDatabase object

  1. Get the number of tabledef objects in the underlying DAO collection by calling CDaoDatabase::GetTableDefCount.

  2. In a loop from 0 to the number of tabledefs, call CDaoDatabase::GetTableDefInfo for each object in the collection.

  3. For each tabledef object, examine the CDaoTableDefInfo object returned by GetTableDefInfo. From this object, you can get:
    • The name of the tabledef object as well as the name of the ODBC source table that the tabledef represents.

    • Whether the table schema is updatable.

    • Tabledef attributes.

    • The date the tabledef object was created and the date it was last updated.

    • The ODBC connection information for the table.

    • The validation rule and validation text for the tabledef, if any.

    • The number of records in the underlying table (obtaining this count might take considerable time for a large table, and the count might be somewhat unreliable).

The MFC Database sample DAOVIEW performs these steps and lists the table names in a list control or a tree control. It then does the same thing for the fields and indexes in the tables and for the other collections in the database: QueryDefs and Relations.

See Also DAO: Where Is..., DAO Recordset, DAO Recordset: Binding Records Dynamically


Database Topics (Data-Bound Controls)

Databinding is a mechanism that allows users to work with data retrieved from a database.

Visual C++ provides a reusable databinding mechanism via ActiveX controls in MFC projects that lets you rapidly develop database applications.

What do you want to know more about?

For more information on how to implement databinding in your Visual C++ application:

  • Using ActiveX Controls

  • Databinding with ActiveX Controls in Visual C++

  • Creating Database Connections

For more information on OLE DB:

  • OLE DB 2.0 Programmer's Reference

  • www.microsoft.com/data/oledb

For more information on ODBC:

  • Geiger, Kyle: Inside ODBC (Microsoft Press, 1995)

  • ODBC 3.6 Programmer's Reference in the Platform SDK, Database and Messaging Services, Microsoft Data Access SDK, Microsoft Open Database Connectivity

  • www.microsoft.com/data/odbc

For more information on writing an ActiveX control that uses databinding:

  • ActiveX Control Writer Toolkit in the Platform SDK, Database and Messaging Services, Microsoft Data Access SDK, OLE DB


Using ActiveX Controls

The topics in this section present an overview of using ActiveX controls.

An ActiveX control is a COM component that supports standard interfaces relating to persistence, connection points, and hosting. These standard interfaces define a protocol by which a control can be hosted in a control container, exchange messages, and handle events.

As COM servers, ActiveX controls have:

Properties Controls have member variables to represent internal state and are implemented as Get and Set accessor functions. A Get function is generated for each accessor method with a propget tag in the .idl file. A Set function is generated for each accessor method with either a propput or propputref IDL tag.

Use wrapper classes or the OLE/COM Object Viewer to determine how accessor functions are defined.
Methods A control's behavior is defined by its public methods. Wrapper classes give you access to a control's methods.

If you do not use wrapper classes, you get access to a control's methods by obtaining a pointer to an interface.

An example of a public method is the Refresh method in the ADO Data Control, which updates the retrieved rowset.
Events A control can generate an event to notify the host that something happened. An example is the OnClick event for the Button control. When the button gets clicked, the button generates an OnClick event. If the control's host has a handler for that event, it executes.
Type Library A type library tells a control container what properties, methods, and events are supported by a control. Type libraries can exist either as separate files (with a .tlb extension) or internally within the control.

Type libraries also contain the control's coclass information. A coclass is a COM class that is identified with a GUID. A coclass contains one or more interfaces that are defined by the control.

To examine type libraries, use the OLE/COM Object Viewer.

The following sections describe the use of an ActiveX control:

Inserting the Control into a Visual C++ Application

Wrapper Classes

Getting Help on Controls

Creating a Database Connection

Setting Control Properties at Design Time

Setting Event Handlers on ActiveX Controls

Modifying a Control's Run-Time Behavior

Redistributing Controls


Inserting the Control into a Visual C++ Application

You can insert an ActiveX control into a project from the Controls and Components Gallery or from within the Dialog editor.

To insert an ActiveX control from the Controls and Components Gallery

  1. Access the Controls and Components Gallery dialog box. See Reusing Code Topics.

  2. Select Registered ActiveX Controls.

  3. Highlight a control and click Insert.

When you insert an ActiveX control from the Controls and Components Gallery into a project, Visual C++

  • Reads the control's type library.

  • Lets you select which wrapper classes to include in the project.

  • Causes the control to appear in the Controls toolbar.

Tip To display the Controls toolbar, right-click in an empty section of the menu bar and select Controls from the shortcut menu.

To insert an ActiveX control from the Dialog editor

  1. Right-click on a dialog box in the Dialog editor.

  2. Select Insert ActiveX Control.

  3. Select a control to insert.

ClassWizard will generate wrapper classes when, or if, you later create a member variable for the control.

Back to Using ActiveX Controls.


Wrapper Classes

When you insert a control, ClassWizard generates wrapper classes for each of the control's internal coclasses. These wrapper classes provide an easy programmatic interface for a control.

ClassWizard usually generates more than one wrapper class. You can identify the control's wrapper class by looking at the class names; the wrapper class should be the control name prefixed by the letter C. For example, you can also identify the control's wrapper by looking at the class declarations; the wrapper class that derives from CWnd, rather than from COleDispatchDriver, is the control wrapper class.

Typically, you only need the wrapper class specific to the control itself. However, some of the Get functions (in the wrapper classes) return pointers to other coclasses as well. If these functions are generated but the wrapper classes for the return values are not generated, the application will not compile. Generally, unless you are familiar with the structure of the coclasses, it is better to generate all of the wrapper classes when you insert the control.

Using CWnd::GetDlgItem also requires wrapper classes since the return value must be cast to the control class. For example:

   CDBList* pDBList = 0;
   pDBList = static_cast<CDBList*>(GetDlgItem(IDC_DBLIST));

Back to Using ActiveX Controls.

See Also

Modifying a Control's Run-Time Behavior


Getting Help on Controls

This section contains topics that discuss how to display information on an ActiveX control:

  • Using the online help.

  • Using the OLE/COM Object Viewer.

Back to Using ActiveX Controls.


Using Online Help

You can access the help file for an ActiveX control via the More Info button from the Controls and Components Gallery. See Reusing Code Topics for more information on using the Controls and Components Gallery dialog box.

Help text is also commonly available from a control's property sheet, which you can access from the Dialog editor. Simply right-click the dialog box and select Properties. You can then use the question mark icon to get help for a property page.

In some cases, a control's help file will have Visual Basic example code. However, there is a direct translation between Visual Basic and Visual C++:

Calling a Method

Method (function) names are the same in Visual Basic and Visual C++.

Visual Basic | Visual C++
dblist.FuncName | dblist.FuncName();
dblist.FuncName x, y | dblist.FuncName(x, y);

Setting a Property

Property names are the same in Visual Basic and Visual C++, but Visual C++ uses Set accessor functions.

Visual Basic | Visual C++
dblist.MyProp = "abc" | dblist.SetMyProp((LPCTSTR)"abc");

Getting a Property

Property names are the same in Visual Basic and Visual C++, but Visual C++ uses Get accessor functions. Note that the Get accessor functions use return values rather than out parameters.

Visual Basic | Visual C++
Dim x as string | CString strTemp("");
x = dblist.MyProp | strTemp = dblist.GetMyProp();

By reading the generated .idl file, you can determine what properties, methods, and events are exposed by a control, as well as see method and accessor function declarations directly. Additional information can be obtained from the control using the OLE/COM Object Viewer.

Back to Getting Help on Controls.


Using the OLE/COM Object Viewer

By reading a control's type library, the OLE/COM Object Viewer lets you view a control's interfaces.

To use the OLE/COM Object Viewer

  1. Start the OLE/COM Object Viewer by either clicking OLE/COM Object Viewer on the Tools menu or by typing oleview at the command line.

  2. Display all registered Automation objects by opening the Automation Objects folder from the Object Classes, Grouped by Component Category.

  3. Scroll down and click the Microsoft ADO Data Control, version 6.0 control. Several tabs will appear in the right pane and the interfaces implemented by the control will display in the Registry tab.

    • If you right-click on a control in the left pane and select View Type Information, the ITypeInfo Viewer will display a reconstructed .idl or .odl file.

    • If you expand the Microsoft ADO Data Control, version 6.0 node in the left pane, you will see a list of the interfaces in the object. If you click on an interface, the registry entry for that interface is displayed in the right pane.

    • If you right-click on an interface and select View, the OLE/COM Object Viewer will display a dialog box showing the GUID for the interface and an option to view type library information, if it is available. Selecting View Type Info will display a portion of a reconstructed .idl file specific to the interface in the ITypeInfo Viewer.

    • In the ITypeInfo Viewer, expanding the tree view and clicking on an interface member will display the accessor method signatures in the right pane.

Back to Getting Help on Controls.


Setting Initial Control Properties

Setting Control Properties at Design Time

Properties of controls can be set at design time using the Dialog editor. When you set a property, the resource editor initializes the control with the specified value. The property still can be changed programmatically.

The DataSource property, which is found in all data-bound controls, allows you to specify the data-source control to which you want to bind. The DataField property is used by simple bound controls to specify a field in a rowset.

Note The General properties tab allows you to specify a control identifier and other properties needed for the .rc file. (The .rc file is later compiled to generate a Windows program's resource code.)

To set a property in the All tab

  1. Insert an ActiveX control into a dialog box.

  2. Right-click on the control in the Dialog editor and select Properties in the shortcut menu.

  3. Select the All tab to display the control's properties and for a given property, enter the initialization value.

Back to Using ActiveX Controls.


Setting Event Handlers on ActiveX Controls

ActiveX controls can be programmed to respond to events. You can use ClassWizard to view the events that are available in a control and to create event handlers. Event handling is commonly done to trap changes in the data-source query. Changes include:

Implementing a Lookup: When a control (like a DBCombo box) changes value, the change event is trapped to update a data-source control's query.

Implementing a Master Detail Relationship: Two data-source controls are added to a dialog box, one for the master portion and a second for the detail portion. Whenever the first data source changes, the second data source's query is updated via an event handler.

Trapping errors: Most controls have an error event from which you can write an error handler. See Error Trapping.

See Mapping Messages to Functions, for more information.

Back to Using ActiveX Controls.


Modifying a Control's Run-Time Behavior

After you insert a control and generate one or more wrapper classes, you can invoke the control's methods and program the control's event handlers. Use the online help to see which methods and events a control supports.

The control's wrapper classes specify the functions you can use to modify the run-time behavior of the control. Simply include the appropriate wrapper class header file, and use the methods. To set a property, look for an accessor method with the property name prefixed by Set. To retrieve a property, look for an accessor method with the property name prefixed by Get. Event handlers can be written after you generate them in ClassWizard.

Since the controls are implemented using Automation, the types passed can only be Automation-safe types such as BSTR and VARIANT. While you can use system calls to allocate and set BSTRs and VARIANTs, you may want to use the ATL wrapper classes (CComBSTR, CComVariant), the Visual C++ COM Compiler support wrapper classes (_bstr_t, _variant_t), or the MFC wrapper class (COleVariant).

If you add a data-source control, ClassWizard will generate wrapper classes for the data-source control's coclasses that manage its internal data objects. These classes do not include all of RDO or ADO, but rather represent internal objects declared in the type library.

If you want to use ADO and RDO directly, you should connect to the ADO or RDO DLLs directly (MSADO15.dll or MSRDO20.dll), either via the Compiler COM Support Classes, which support the #import directive, or via the respective SDK.

Back to Using ActiveX Controls.


Redistributing Controls

Since ActiveX controls are dynamically linked, you need to redistribute the ActiveX controls with the applications that use them. The Controls and Components Gallery will display all ActiveX controls on your computer. However, when adding an ActiveX control to a redistributable project, you must consider the following legal and technical issues:

Visual Studio Licensed Controls: Since Visual Studio bundles several development tools in addition to Visual C++, Visual Studio licensees will also have ActiveX controls specific to the other tools installed onto their computer. For example, the Chart control is distributed with Visual Basic, which also ships in Visual Studio. Thus if you are using Visual C++ as a part of a Visual Studio license, you will be able to use the Chart control. However if you purchased only Visual C++, you will not have a license to redistribute it.

Design Time and Run Time Licenses: Microsoft distributes some controls from third parties. These controls may come with a requirement for both a Design-Time license for development, and a Run-Time license for distribution. See the \Redist\Redist.wri file on Visual C++ CD 1 for more information on redistribution issues.

Distributing Dependent Files: Often, it is not enough to ship the ActiveX control with your application. The control may come with other dependent files that should be distributed along with the ActiveX control. For example, the new data-bound controls should be distributed with the binding manager (MSBind.dll) and the formatting objects (MSStdFmt.dll) DLLs. These objects provide support for common databinding functionality, and the data-bound controls will not bind properly without them.

Back to Using ActiveX Controls.


Databinding with ActiveX Controls in Visual C++

Databinding is implemented via two types of ActiveX controls: data-source controls and data-bound controls.

Data-Source Controls

A data-source control is responsible for encapsulating a database query and the retrieved rowset. The Microsoft data-source controls provide a user interface consisting of a series of buttons to iterate through the data. Visual C++ offers two data access technologies for data-source controls: ADO and RDO.

Data-Bound Controls

A data-bound control is responsible for presenting the data. Data-bound controls connect to data-source controls to receive data and present the data through a variety of user interfaces. A Visual C++ application can also bind variables to data values set in the data-bound controls; see CWnd::BindProperty.

What do you want to know about databinding?

Data Access: ADO and RDO

ActiveX Controls that Support Databinding

ADO Databinding

RDO Databinding

Wrapper Classes

Setting Event Handlers on ActiveX Controls

Error Trapping

Limitations of Databinding


Data Access: ADO and RDO

Two underlying technologies support data-source or data-bound controls:

ADO

ADO is a COM wrapper of OLE DB that facilitates writing data access applications (consumers). OLE DB is a COM-based universal data access technology, allowing you to use any data source, not just indexed, sequential access methods (ISAMs) and SQL-based databases.

OLE DB providers can access data from a variety of data sources and is not limited to SQL queries to retrieve data but rather can use queries as defined in the provider.

RDO

RDO is the COM wrapper of ODBC. ODBC, a C-based API, allows general-purpose (heterogeneous) data access. However, RDO relies on SQL as the command language to access data.

As of this writing, Microsoft does not plan to further develop RDO. For this reason, you may consider using the ADO-based data-access controls rather than the RDO data-access controls.

The main differences between ADO and RDO data controls are:

Data-Bound Controls

RDO data-bound controls use the ICursor interfaces; ADO controls use the OLE DB IRowset interface. In both cases, the interfaces used by the controls return a rowset.

The RDO-based data-bound controls were designed to work best with Visual Basic. As such, some functionality of RDO data-bound controls, most notably in formatting, is not available in Visual C++ made applications. This problem is not present in the ADO databinding controls.

Data-Source Controls

ADO data-source controls implement the IDataSource interface and RDO data-source controls implement the IVBDSC interface. You can call an IDataSource method to receive an IRowset interface pointer. Similarly, you can call an IVBDSC method to get an ICursor interface pointer.

Back to Databinding with ActiveX Controls in Visual C++.


ActiveX Controls that Support Databinding

A data-source control is used on your dialog box to make a connection to a data source. One or more data-bound controls are then connected to a data-source control to display data to a user.

Microsoft Visual C++ 6.0 distributes controls in the Os\System folder on the product CD. The controls are:

Data-Source Controls

ADO Data-Bound Controls

RDO Data-Bound Controls

ADO and RDO Data-Bound Controls

Back to Databinding with ActiveX Controls in Visual C++.


Data-Source Controls

A data-source control lets you define a query with which to access data. You then connect data-bound controls to a data source.

Control | Support Files
Microsoft ADO Data Control | Msadodc.ocx; help file is Adodc98.chm.
Microsoft RemoteData Control | Msrdc20.ocx; help file is RDO98.chm.

See Data Access: ADO and RDO for more information.

Back to ActiveX Controls that Support Databinding.


ADO Data-Bound Controls

The following data-bound controls display data from the ADO Data Control. See Inserting the Control into a Visual C++ Application and Setting Control Properties at Design Time for information on using ActiveX controls.

Control Name and Support Files Description
Microsoft DataCombo

Msdatlst.ocx

DBList98.chm

 The DataCombo control allows retrieved data to appear in a drop-down combo box.

To link the DataCombo control to a data source

  1. Set the DataSource and the RowSource properties to an ADO Data Control.

  2. Set the DataField and ListField properties to the desired fields.

DataSource and DataField govern the active value of the control. RowSource and ListField allow the display of column data other than the current record. You can also set BoundColumn; this property represents the value of the control when it is made into a variable in an MFC application.
Microsoft DataGrid

Msdatgrd.ocx

DBGrid98.chm

 DataGrid can hold text data, but not linked or embedded objects. The AllowAddNew, AllowDelete, and AllUpdate properties allow the DataGrid to modify data.
Microsoft DataList

Msdatlst.ocx

DBList98.chm

 The DataList control allows retrieved data to appear in a drop-down list box.

To link the DataList control

  1. Set the DataSource and the RowSource properties to an ADO Data Control.

  2. Set the DataField and ListField properties to the desired fields.

DataSource and DataField govern the active value of the control. RowSource and ListField allow the display of column data other than the current record. You can also set the BoundColumn value. This value represents the value of the control when it is made into a variable in an MFC application.
Microsoft DataRepeater

Msdatrep.ocx

DatRpt98.chm

 The DataRepeater control is a composite control; a control that hosts other controls. It allows you to specify a control to repeat, and when bound, displays the selected control for each record retrieved. The DataRepeater will then allow end users to scroll through the retrieved records.

To link the DataRepeater control

  1. In the All property tab, set the DataSource property to an ADO Data Control.

  2. In the All property tab, select a control to repeat for the Repeated Control Name property.

  3. Once a control is selected, go to the RepeaterBindings tab.

  4. Set a property name to bind. The drop-down box will enumerate bindable properties in the control to be repeated.

  5. Set a data field. The drop-down box will enumerate column names returned from the bound ADO Data Control.

  6. Click on the Add button to add the binding. The RepeaterBindings list box will then populate with the new binding.

The DataRepeater control also ships separately with Visual Studio 6.0.
Microsoft Hierarchical FlexGrid

Mshflxgd.ocx

MsHFlx98.chm

 The Hierarchical FlexGrid control displays tabular data. Unlike the DataGrid, it is strictly read-only. However, it can sort, merge, and format tables containing strings and pictures. Additionally, the Hierarchical FlexGrid differs from its predecessor, the FlexGrid, in that it can display both summary data and detail data.

A hierarchical rowset is required to display summary-detail information in the Hierarchical FlexGrid control. To create a hierarchical rowset for this control, the Microsoft Data Shape Provider is required in combination with the ADO Data Control.

To use the Hierarchical FlexGrid

  1. Use the ADO Data Control to set the ConnectionString property to specify the Microsoft Data Shape Provider. For example:
    Provider=MSDataShape.1;Data Source=myPubsDataSource;User ID=sa

  2. Set the RecordSource property to use Microsoft Data Shape Provider syntax to create a hierarchical rowset. For example:

    SHAPE {select * from authors} APPEND ({select * from titleauthor} AS chapter RELATE au_id TO au_id)

    3.

  3. Set the DataSource property of the Hierarchical FlexGrid control to the ADO Data Control configured above.
    4.

For additional information on data shaping see the topic Hierarchical Cursors and Data Shaping in the ADO Programmer's Reference.

Microsoft Chart

Mschart.ocx

MSchrt98.chm

The Chart control displays an array of data as a graph. It can display both two-dimensional and three-dimensional graphs. When data-bound, it treats the retrieved rowset as an array of data.

To link the Chart control

  1. Set the DataSource property to an ADO Data Control.
    2.

It is recommended that the ADO Data Control's database query retrieve a rowset of aggregate information such as count(*), sum(*), min(*), and max(*).

Previous versions of the MS Chart control were RDO based.

Note   The Chart control ships with Visual Studio 6.0 (not Visual C++), so you must have a Visual Studio 6.0 license to redistribute it.

Back to ActiveX Controls that Support Databinding.


RDO Data-Bound Controls

The following data-bound controls display data from the RDO RemoteData Control. See Inserting the Control into a Visual C++ Application and Setting Control Properties at Design Time for information on using ActiveX controls.

Control Name and Support Files Description
Microsoft DBCombo

Dblist32.ocx

DBList98.chm

 The DBCombo control allows retrieved data to appear in a drop-down combo box.

To connect the DBCombo control to a data source

  1. Set the DataSource and the RowSource properties to an RDO RemoteData Control.

  2. Set the DataField and ListField properties to the desired fields.

DataSource and DataField govern the active value of the DBCombo control. RowSource and ListField allow the display of column data other than the current record. You can also set the BoundColumn property; this property represents the value of the control when it is made into a variable in an MFC application.
Microsoft DBGrid

Dbgrid32.ocx

DBGrid96.hlp

 The DBGrid control displays retrieved data. It can hold text data, but not linked or embedded objects. The AllowAddNew, AllowDelete, and AllUpdate properties allow the DBGrid to modify data.
Microsoft DBList

Dblist32.ocx

DBList98.chm

 The DBList control allows retrieved data to appear in a drop-down list box.

To connect the DBList control to a data source

Follow the instructions for connecting a DBCombo control to a data source.
Microsoft FlexGrid

Msflxgrd.ocx

MsHFlx98.chm

 The FlexGrid control displays tabular data. Unlike the DBGrid, it is read-only. It has different formatting capabilities than the DBGrid control; it can sort, merge, and format tables containing strings and pictures.

Back to ActiveX Controls that Support Databinding.


ADO and RDO Data-Bound Controls

The following data-bound controls display data from both the ADO Data Control and the RDO RemoteData Control. These are known as the simple data-bound controls because they only display one value at a time.

See Inserting the Control into a Visual C++ Application and Setting Control Properties at Design Time for information on using ActiveX controls.

To insert a simple data-bound control and connect it to a data source

  1. Set the DataSource property to a data-source control.

  2. Set the DateField or DataField property to a column with an appropriate data type for the control.
Control Name and Support Files | Description
Calendar Mscal.ocx MSCal.hlp | The Calendar control displays a view of a given month. It displays the current date highlighted in the month based on the date field returned by the data-source control; if the value is not valid, it simply displays the current month.
Microsoft Date and Time Picker Mscomct2.ocx Cmctl298.chm | The Date and Time Picker control allows a user to pick a date and time from a drop-down calendar, and display it as formatted text. The format date strings use the same arguments as specified in the Visual Basic Programmer's Reference.
Microsoft Masked Edit Msmask32.ocx Masked98.chm | The Masked Edit control allows users to work with text data via a formatting mask. Formatting is supported by a Visual Basic specific internal interface, IVBFormat, and thus is not accessible programmatically (even though wrapper classes will be generated for the formatting properties).
Microsoft MonthView MSComct2.ocx Cmctl298.chm | The MonthView control displays a view of a given month, with the current date highlighted. The MonthView control is one of the new common controls, designed with Internet issues in mind. It provides a wider range of functionality than the Calendar control, such as multiple selection of dates and additional options for marking days.
Microsoft RichText Richtx32.ocx RtfBox98.chm | The RichText control is based on the RichText 1.0 component from Microsoft Word. It allows users to edit text with most common text editing features. It can load, link, and embed OLE objects. It also allows users to print a selection of text. It persists files in RTF format using the LoadFile and SaveFile methods.

Back to ActiveX Controls that Support Databinding.


ADO Databinding

This section discusses the use of the databinding ActiveX controls that are built with ADO.

What do you want to know about ADO ActiveX control databinding?

Using ADO Databinding in Visual C++

Setting Event Handlers on ActiveX Controls

Updating Data with the ADO Data Control


Using ADO Databinding in Visual C++

Using ADO databinding in Visual C++ requires the following steps.

  • Add an ADO Data Control.

  • Point to a data source.

  • Specify the record source (SQL query or data retrieval language).

  • Add an ADO data-bound control.

  • Connect the data-bound control to an ADO Data Control.

  • Select the fields to bind to the ADO Data Control's record source.

To use ADO databinding in Visual C++

  1. Create an MFC Dialog application or MFC Formview application using the MFC AppWizard.

  2. Add the Microsoft ADO Data Control to the dialog box; see Inserting the Control into a Visual C++ Application.

  3. Point the ADO Data Control to your OLE DB data source.
    1. Right-click on the ADO Data Control and select Properties from the shortcut menu.

    2. On the Control tab, select the Use Connection String. You can use the supplied provider or you can delete it.

    3. Select Build. If you deleted the provider from Use Connection String, you will now be able to define one. After you define the provider, access the properties of the ADO Data Control again and select Build again to continue.

      If a provider is defined in Use Connection String before you select Build, you will now be able to define the data link properties. This displays the DataLink Wizard.

    4. Change the Provider if necessary, and define Location and Data Source values, as appropriate for your provider. For example, if you are using a SQL Server provider, Location specifies the database server and Data Source specifies the database. If you are using an ODBC provider, the Data Source corresponds to the ODBC DSN.

    5. Select the Authentication tab and set values for User Name and Password, if required by the data source.

    6. Return to the Connection tab and click Test Connection to test the data source. Scroll to the end of the Results window to see if the test passed. If it failed, check the configuration of your data source. Common errors include invalid passwords and incorrect values for the Location and Data Source fields.

    7. Exit the DataLink Wizard and return to the property sheet for the ADO Data Control.
  4. In the RecordSource tab, enter a query into the Command Text (SQL). The data-bound controls can bind to the results of this query. The query will usually be SQL. However, some OLE DB providers do not use SQL.

  5. Set any other ADO Data Control properties as needed and close the property sheet for the ADO Data Control.

  6. Add a data-bound control. For example, add the DataGrid control. (Do not confuse the DataGrid control with the RDO DBGrid control.)

  7. Set the DataGrid's properties.
    1. Right-click on the DataGrid and select Properties from the shortcut menu.

    2. Select the All tab and set the DataSource property to the ADO Data Control. Click on the DataSource drop-down list and find the ID of the ADO Data Control. The default ID name is IDC_ADODC1.
  8. To run in test mode, use CTRL+T. You will be able to scroll through the data. Use the Esc key or close the dialog box to end test mode.

If you compile and run the program, you will be able to scroll through the data as well.

Back to Databinding with ActiveX Controls in Visual C++.


Updating Data with the ADO Data Control

ADO Data Control data can be either read-only or modifiable. To create an application that modifies data using ADO Data Control, do the following.

  1. Set ADO Data Control CursorLocation property. Options are:
    • Server Side

    • Client Side
  2. Set ADO Data Control LockType property. The optimistic concurrency is recommended.

  3. Set ADO Data Control CursorType property. Options are:
    • Keyset Cursor

    • Dynamic Cursor

    • Static Cursor

    Make sure the OLE DB provider supports the chosen option.

  4. Set the data-bound control's properties, as needed, to allow updatability. Note that some controls do not allow updating.

Refer to the ADO documentation for more information on these properties; see Getting Help on Controls.

Back to Using ADO Databinding in Visual C++.


RDO Databinding

This section discusses the use of the databinding ActiveX controls that are built with RDO.

What do you want to know about RDO ActiveX databinding?

Using RDO Databinding in Visual C++

Updating Data with the RDO RemoteData Control

Model for Hosting RDO Data Controls in a Container


Using RDO Databinding in Visual C++

To use RDO databinding in Visual C++, you need to add an RDO RemoteData Control and point to a data source and a record source (SQL query). You also need to add an RDO data-bound control, point it to an RDO RemoteData Control, and select the fields to bind to the RDO RemoteData Control's record source.

To use RDO databinding in Visual C++

  1. Configure an ODBC data source, if you have not already done so.

  2. Create an MFC Dialog application or MFC Formview application using the MFC AppWizard.

  3. Add the Microsoft RemoteData Control (RDO RemoteData Control) to the dialog box; see Inserting the Control into a Visual C++ Application.

  4. Point the RDO RemoteData Control to your ODBC data source.
    1. Right-click on the control and select Properties from the shortcut menu.

    2. Select the Control tab.

    3. Set DataSource to your ODBC data source.

    4. As needed, set the username and password for your ODBC data source. Leave blank if the data source does not require a username or password.

    5. Enter an SQL query into the SQL property. The data-bound controls can bind to the results of this query.
  5. Set any other RDO RemoteData Control properties as needed.

  6. Add a data-bound control. For example, add the DBGrid Control and set the data source as follows.
    1. Right-click on the DBGrid and select Properties from the shortcut menu.

    2. Click on the All tab.

    3. Set the DataSource property to the RDO RemoteData Control. Click on the drop-down combo box for the property and find the ID of the RDO RemoteData Control. The default ID name is IDC_REMOTEDATACTL1.
  7. To run in test mode, use CTRL+T. You will be able to scroll through the data. Use the Esc key or close the dialog box to end test mode.

If you compile and run the program, you will be able to scroll through the data as well.

Back to Databinding with ActiveX Controls in Visual C++.


Updating Data with the RDO RemoteData Control

RDO RemoteData Control data can be either read-only or modifiable. To create an application that modifies data using RDO RemoteData Control, do the following:

  1. Set the RDO RemoteData Control CursorDriver property.
    • Server Side cursors store returned data on the server.

    • ODBC Client Side cursors store data in the client's local storage.

    • Client Batch Side cursors use a cursor library designed to deal with concurrency issues.

    • No Cursor option is used when an action query is performed, and thus no cursor is necessary.
  2. Set the RDO RemoteData Control LockType property. The optimistic concurrency based on resultset option is recommended.
    • Read-only concurrency should not be used if you want data to be modifiable.

    • Pessimistic concurrency locks data during update so that other users will not be in danger of committing incompatible data changes.

    • Optimistic concurrency does not lock data, but if during commit, it detects that another client has posted an incompatible state, the RDO RemoteData Control throws an error.
  3. Set the RDO RemoteData Control ResultsetType property. Make sure the ODBC driver supports the chosen options.
    • When Create Static Cursor is chosen, the changes are not detected until the cursor is closed and reopened.

    • When Create Keyset Cursor is chosen, the cursor allows inserts, updates, and deletes, at will, within the keyset cursor itself.
  4. Set the data-bound control as needed to allow updatability. Note that some controls do not allow updating.

See the documentation on the RDO RemoteData Control for information on how to use these objects; see Getting Help on Controls.

Back to Using RDO Databinding in Visual C++.


Model for Hosting RDO Data Controls in a Container

A container hosts an RDO data-source control as follows

  1. The container obtains an IVBDSC interface from the data-source control. If it cannot find IVBDSC, then it is not a data-source control.

  2. The container obtains the ICursor interfaces from the data-source control. These interfaces supply a Cursor object that can be manipulated by a client.

  3. The container hooks up to the data-source control's INotifyDBEvents interface. This interface allows the container to receive notifications from the data-source control. The container should support the INotifyDBEventsSink interface in order to do this.

A container hosts an RDO data-bound control as follows

  1. The control supports the IBoundObject interface and the container supports the IBoundObjectSite interface. The control obtains the container's IBoundObjectSite interface, and the container obtains the IBoundObject interface from the control.

  2. The control supports the IPropNotifySink interface, and hooks up with the container. This allows the container to receive notifications from the control.

  3. If the control supports INotifyDBEventsSink, it can receive notifications from an RDO data-source control after connecting with the data-source control's INotifyDBEvents interface.

  4. The control then can receive cursor objects from the data-source control (directly or through the container). The cursors can then be manipulated and scrolled. At this point, the RDO data-bound control is successfully bound.

Back to Using RDO Databinding in Visual C++.


Error Trapping

In databinding, error trapping comes from two sources, error events or error objects.

Error Trapping via Error Events

Both the ADO Data Control and the RDO RemoteData Control data-source controls have error events. Typically you set an error event handler. The event handlers have the following signature.

void CMyDlg::OnErrorAdodc1(long ErrorNumber,
                           BSTR* FAR Description,
                           long Scode,
                            LPCTSTR Source,
                           LPCTSTR HelpFile,
                           long HelpContext,
                           BOOL FAR* fCancelDisplay)

Usually the Description field is populated, but the ErrorNumber and Scode fields are only populated in the event of COM errors. A standard event handler is to display the Description field in a message box. For example:

{
   USES_CONVERSION;
// note: have to include the ATL file ATLConv.h to use the ATL conversion macros
   ::AfxMessageBox(OLE2T(*Description), MB_OK);
}

However, the ADO Data Control and RDO RemoteData Control are already set up to trap error events, so no coding is necessary.

Error Trapping via Error Objects

Both ADO and RDO have error objects. When generating wrapper classes, the RDO RemoteData Control generates wrappers for error objects, but ADO Data Control does not.

The ADO data Control automatically displays ADO error messages.

Back to Databinding with ActiveX Controls in Visual C++.


Limitations of Databinding

Databinding is a powerful way to create data applications quickly. However the current databinding controls architecture is inherently 2-tier. Some issues:

Scalability

ADO data-bound controls can only access data from the ADO Data Control. RDO data-bound controls can only access data from the RDO RemoteData Control. For RDO RemoteData Control, there is no workaround but to use a 2-tier architecture, which results in the database server receiving all data retrieval requests directly. To avoid directly connecting to the database server, write a provider that allows access to middle-tier business and data objects. The ADO Data Control connects to these objects, rather than the database server. Such middle tier objects can be cached and managed in a transaction server such as Microsoft Transaction Server. Refer to the OLE DB Templates provider sample ATLMTO for an example of writing a provider exposing data from a middle tier object. Refer to Microsoft Transaction Server for more information on OLE DB provider requirements for transactions.

Versioning and Distribution

When new versions of controls are released, the application will have to be tested with the new versions. If another application is installed on a user's computer, and it has a different version of the controls, the application will have to be checked. Finally, when new versions of controls are released, the new controls will have to be distributed to application users.

Drivers and Providers

Databinding is only as good as the ODBC driver or OLE DB provider you are using. Since the drivers and providers are responsible for exposing data to data-source controls, it is important to ensure that the driver or provider supports the functionality that you need. Once you select a driver or provider, you must also ensure that your users have the driver or provider installed. This includes installing any middleware that the driver or provider requires. For example, for ODBC Oracle connectivity, the user should have installed not only an ODBC Oracle driver, but also Oracle's SQL*Net middleware. For connectivity to Oracle 7.3 servers, the Microsoft Oracle ODBC driver is recommended.

Programmability

Since ActiveX controls were designed to be black-box components, programmability is limited to a developer's access to the control's interfaces. In the databinding model in the resource editor, this is implemented via wrapper classes generated by ClassWizard. If ClassWizard is unable to detect a coclass, then no wrapper class is generated, and there is no programmatic access.

Despite these limitations, databinding affords a way to rapidly prototype data applications using Visual C++. If speed of development is important, then databinding should be considered when designing your application.

Back to Databinding with ActiveX Controls in Visual C++.


Creating Database Connections

To use databinding, you must configure a data source. When using the ADO Data Control, you must configure an OLE DB connection. When using the RDO RemoteData Control, you must create an Open Database Connectivity (ODBC) connection. Since Visual C++ ships with an OLE DB provider for ODBC data sources, the ADO Data Control can also make use of ODBC connections.

ODBC Connections

Oracle Connections


ODBC Connections

ODBC connections are configured in the system control panel. ODBC connections can be made against any data source for which an ODBC driver has been installed. Visual C++ 6.0 ships drivers for Text files, Access, FoxPro, Paradox, dBase, Excel, SQL Server, and Oracle. When you create an ODBC connection, it automatically receives a Data Source Name (DSN). The DSN is subsequently used to identify connections in data-source controls, such as ADO Data Control and RDO RemoteData Control.

OLE DB Connections No additional work is necessary to configure an OLE DB connection. For example, if an ODBC data source is created, the OLE DB provider for ODBC automatically detects it.

To configure an ODBC data source

  1. Click on the Start button, select Settings, and then Control Panel.

  2. In Control Panel, select 32bit ODBC (Windows 95) or ODBC (Windows NT).

  3. Select the User DSN or System DSN tab. User DSN lets you create user-specific data-source names and System DSN lets you create data-sources available to all users.

  4. Click Add to display a list of locally installed ODBC drivers.

  5. Select the driver corresponding to the type of indexed sequential access method (ISAM) or database you want to connect to and click Finish.

  6. Follow the instructions specific to the driver. After closing, the DSN is now available for use.

When generating a DSN for some ODBC driver types, you need to know the location of the actual file. For example when creating an Access DSN, you need to know the location of the .mdb file. Also, you should have a valid username and password. For example, the system username for most Access systems is admin.

When creating an Oracle DSN, you should know the SQL*Net connection string.

Back to Creating Database Connections.


Oracle Connections

When configuring either an Oracle ODBC DSN or an OLE DB connection, you must have Oracle's SQL*Net client-side components installed. SQL*Net is Oracle's network transport layer. Most Oracle ODBC drivers, including Microsoft's driver and the Microsoft OLE DB Oracle provider map, call directly to this SQL*Net layer.

After SQL*Net is configured, note your SQL*Net connect string. Typically this consists of a specifier for the Oracle database server name, and the network protocol type (TCP/IP, named pipes, etcetera.). Often, the SQL*Net connect string is mapped to an alias. In this case it is only necessary to note the alias. For information on how to configure SQL*Net contact your Oracle DBA, refer to the SQL*Net documentation, or refer to your Oracle ODBC driver help file for an example of a connection string.

Back to Creating Database Connections.


Database Topics (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The Microsoft Foundation Class Library (MFC) supplies classes for programming with Open Database Connectivity (ODBC). These classes are distinct from the newer MFC classes supplied for programming with Data Access Objects (DAO).

Frequently Asked Questions About MFC Database Support

  • What data sources can I access with DAO and ODBC?

  • Can I call DAO or ODBC APIs directly while using the classes?

  • What ODBC drivers are provided?

  • What ODBC drivers are installed by default?

What do you want to know more about?

  • ODBC — the Open Database Connectivity standard and API

  • What MFC support is supplied for ODBC programming

  • What ODBC drivers are available

  • Installing MFC ODBC support

  • Should I Use DAO or ODBC?

  • Connecting to ODBC data sources

  • Record field exchange (RFX) between a database and a recordset object

  • ODBC recordsets

  • Structured Query Language (SQL) for ODBC

  • Database transactions

  • Determining the schema of an ODBC data source at run time

  • Programmatically configuring an ODBC data source

  • Programmatically creating a table in an ODBC data source

  • Fetching records in bulk

  • Customizing my recordset’s SQL statement

  • Making direct SQL calls

  • Making direct calls to the ODBC API

  • How do the database classes work with MFC’s document/view architecture?


ODBC and MFC

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Important To use the MFC database classes for targeting a Win32 platform (such as Windows NT), you must have the 32-bit ODBC driver for your data source. Some drivers are included with Visual C++; others can be obtained from Microsoft and other vendors. For more information, see the article ODBC Driver List.

This article introduces the main concepts of the Microsoft Foundation Class Library’s ODBC-based database classes and provides an overview of how the classes work together. (For information about using the MFC DAO classes instead, see the article Database Topics (DAO).) Topics covered in this article include:

  • Connecting to a data source

  • Selecting and manipulating records

  • Displaying and manipulating data in a form

  • Working with documents and views

  • Access to ODBC and SQL

  • Further reading about the MFC ODBC classes

The MFC database classes based on ODBC are designed to provide access to any database for which an ODBC driver is available. Because the classes use ODBC, your application can access data in many different data formats and different local/remote configurations. You do not have to write special-case code to handle different database management systems (DBMSs). As long as your users have an appropriate 32-bit ODBC driver for the data they wish to access, they can use your program to manipulate data in tables stored there.


Connecting to a Data Source

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

An ODBC data source is a specific set of data, the information required to access that data, and the location of the data source, which can be described using a data-source name. From your program’s point of view, the data source includes the data, the DBMS, the network (if any), and ODBC.

To access data provided by a data source, your program must first establish a connection to the data source. All data access is managed through that connection.

Data-source connections are encapsulated by class CDatabase. Once a CDatabase object is connected to a data source, you can:

  • Construct recordsets, which select records from tables or queries.

  • Manage transactions, batching updates so all are “committed” to the data source at once (or the whole transaction is “rolled back” so the data source is unchanged) — if the data source supports the required level of transactions.

  • Directly execute Structured Query Language (SQL) statements.

When you finish working with a data-source connection, you close the CDatabase object and either destroy it or reuse it for a new connection. For more information about data-source connections, see the article Data Source (ODBC).


Selecting and Manipulating Records

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Normally when you select records from a data source using an SQL SELECT statement, you get a “result set” — a set of records from a table or a query. With the database classes, you use a “recordset” object to select and access the result set. This is an object of an application-specific class that you derive from class CRecordset. When you define a recordset class, you specify the data source to associate it with, the table to use, and the columns of the table. Either ClassWizard or AppWizard creates a class with a connection to a specific data source. The wizards write the GetDefaultSQL member function of class CRecordset to return the table name. For more information on using the wizards to create recordset classes, see the articles Overview: Creating a Program That Supports a Database and ClassWizard: Database Support.

Using a CRecordset object at run time, you can:

  • Examine the data fields of the current record.

  • Filter or sort the recordset.

  • Customize the default SQL SELECT statement.

  • Scroll through the selected records.

  • Add, update, or delete records (if both the data source and the recordset are updatable).

  • Test whether the recordset allows requerying, and refresh the recordset’s contents.

When you finish using the recordset object, you close and destroy it. For more information about recordsets, see the article Recordset (ODBC).


Displaying and Manipulating Data in a Form

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Many data-access applications select data and display it in fields in a form. The database class CRecordView gives you a CFormView object directly connected to a recordset object. The record view uses dialog data exchange (DDX) to move the values of the fields of the current record from the recordset to the controls on the form, and to move updated information back to the recordset. The recordset, in turn, uses record field exchange (RFX) to move data between its field data members and the corresponding columns in a table on the data source.

You can use AppWizard or ClassWizard to create the record view class and its associated recordset class in conjunction.

The record view and its recordset are destroyed when you close the document. For more information about record views, see the article Record Views. For more information about RFX, see the article Record Field Exchange (RFX).


Working with Documents and Views

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The Microsoft Foundation Class Library relies on a document/view architecture for many of its features. Typically a document stores your data, and a view displays it within the client area of a frame window and manages user interaction with the data. The view communicates with the document to obtain and update the data. You can use the database classes with the framework or without it.

For more information about using database classes in the framework, see the article MFC: Using Database Classes with Documents and Views.

By default, AppWizard creates a skeleton application with no database support. But you can select options to include minimal database support or more complete form-based support. For more information about AppWizard options, see the article Overview: Creating a Program That Supports a Database.

You can also use the database classes without using the full document/view architecture. For more information, see the article MFC: Using Database Classes Without Documents and Views.


Access to ODBC and SQL

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The Microsoft Foundation Class Library encapsulates many Windows API calls and still lets you call any Windows API function directly. The database classes give you the same flexibility with regard to the ODBC API. While the database classes shield you from much of the complexity of ODBC, you can call ODBC API functions directly from anywhere in your program.

Similarly, the database classes shield you from having to work much with SQL, but you can use SQL directly if you wish. You can customize recordset objects by passing a custom SQL statement (or setting portions of the default statement) when you open the recordset. You can also make SQL calls directly using the ExecuteSQL member function of class CDatabase.

For more information, see the articles ODBC: Calling ODBC API Functions Directly and SQL: Making Direct SQL Calls (ODBC).


Further Reading About the MFC ODBC Classes

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The following articles further explain the concepts and techniques introduced in this article:

  • Overview: Creating a Program That Supports a Database

  • ClassWizard: Database Support

  • Data Source (ODBC)

  • Dynaset

  • Exceptions: Database Exceptions

  • MFC: Using Database Classes with Documents and Views

  • MFC: Using Database Classes Without Documents and Views

  • ODBC

  • ODBC Administrator

  • Record Field Exchange (RFX)

  • Recordset (ODBC)

  • Record Views

  • Serialization: Serialization vs. Database Input/Output

  • Snapshot

  • SQL

  • Transaction (ODBC)

A good place to begin your reading is with the article Recordset (ODBC).

In the Class Library Reference see CDatabase, CRecordset, CRecordView, CFieldExchange, CDBException. In Tutorials, see Creating a Database Application.

See Also Database Topics


ODBC Classes and Threads

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Beginning with MFC 4.2, there is multithreading support for the MFC ODBC classes. Note, however, that MFC does not provide multithreading support for the DAO classes.

The multithreading support for the ODBC classes has some limitations. Because these classes wrap the ODBC API, they are restricted to the multithreading support of the components on which they are built. For example, there are many ODBC drivers that are not thread-safe; therefore, the MFC ODBC classes will not be thread-safe if you use them with one of these drivers. You should verify whether your particular driver is thread-safe.

When creating a multithreaded application, you should be very careful in using multiple threads to manipulate the same object. For example, using the same CRecordset object in two threads may cause problems when retrieving data; a fetch operation in one thread may overwrite the data fetched in the other thread. A more common use of the MFC ODBC classes in separate threads would be to share an open CDatabase object across threads in order to use the same ODBC connection, with a separate CRecordset object in each thread. Note that you should not pass an unopened CDatabase object to a CRecordset object in another thread.

Important If you must have multiple threads manipulate the same object, you should implement the appropriate synchronization mechanisms, such as critical sections. Be aware that certain operations, such as Open, are not protected. You should be sure that these operations will not be called concurrently from separate threads.

For more information about creating multithreaded applications, see the article Multithreading Topics.

See Also Database Topics (General)


ODBC

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

In addition to an overview of Open Database Connectivity (ODBC), this article explains:

  • How ODBC works with the database classes.

  • How ODBC drivers work with dynasets.

  • What ODBC components you need to redistribute with your applications.

You will also want to read the related article ODBC: The ODBC Cursor Library.

Notes ODBC data sources are accessible through the MFC ODBC classes, as described in this article, or through the MFC Data Access Object (DAO) classes. For information about the DAO classes, see the article DAO and MFC.

The MFC ODBC classes support Unicode and multithreading. For more information about the multithreading support, see the article ODBC Classes and Threads

ODBC is a call-level interface that allows applications to access data in any database for which there is an ODBC driver. Using ODBC, you can create database applications with access to any database for which your end-user has an ODBC driver. ODBC provides an API that allows your application to be independent of the source database management system (DBMS).

ODBC is the database portion of the Microsoft Windows Open Services Architecture (WOSA), an interface which allows Windows-based desktop applications to connect to multiple computing environments without rewriting the application for each platform.

The following are components of ODBC:

  • ODBC API

    A library of function calls, a set of error codes, and a standard Structured Query Language (SQL) syntax for accessing data on DBMSs.

  • ODBC Driver Manager

    A dynamic-link library (ODBC32.DLL) that loads ODBC database drivers on behalf of an application. This DLL is transparent to your application.

  • ODBC database drivers

    One or more DLLs that process ODBC function calls for specific DBMSs. For a list of supplied drivers, see the article ODBC Driver List.

  • ODBC Cursor Library

    A dynamic-link library (ODBCCR32.DLL) that resides between the ODBC Driver Manager and the drivers and handles scrolling through the data.

  • ODBC Administrator

    A tool used for configuring a DBMS to make it available as a data source for an application.

An application achieves independence from DBMSs by working through an ODBC driver written specifically for a DBMS rather than working directly with the DBMS. The driver translates the calls into commands its DBMS can use, simplifying the developer’s work, and making it available for a wide range of data sources.

The database classes support any data source for which you have an ODBC driver. This might, for example, include a relational database, an Indexed Sequential Access Method (ISAM) database, a Microsoft Excel spreadsheet, or a text file. The ODBC drivers manage the connections to the data source, and SQL is used to select records from the database.

See the article ODBC Driver List for a list of ODBC drivers included in this version of Visual C++ and for information about obtaining additional drivers.

The ODBC Software Development Kit (SDK) is provided on the MSDN Library CD. For more information on ODBC, see the ODBC SDK Programmer’s Reference, and the ODBC API Reference Help system.


ODBC and the Database Classes

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The MFC ODBC database classes encapsulate the ODBC API function calls you would normally make yourself in the member functions of the CDatabase and CRecordset classes. For example, the complex ODBC call sequences, binding of returned records to storage locations, handling of error conditions, and other operations are managed for you by the database classes. As a result, you use a considerably simpler class interface to manipulate records through a recordset object.

Note ODBC data sources are accessible through the MFC ODBC classes, as described in this article, or through the MFC Data Access Object (DAO) classes. For information about the DAO classes, see the article DAO and MFC.

Although the database classes encapsulate ODBC functionality, they do not provide a one-to-one mapping of ODBC API functions. The database classes provide a higher level of abstraction, modeled after data-access objects found in Microsoft Access and Microsoft Visual Basic. For more information, see What Is the MFC Database Programming Model?.


ODBC Driver Requirements for Dynasets

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

In the MFC ODBC database classes, dynasets are recordsets with dynamic properties — they remain synchronized with the data source in certain ways. MFC dynasets (but not forward-only recordsets) require an ODBC driver with Level 2 API conformance. If the driver for your data source conforms to the Level 1 API set, you can still use both updatable and read-only snapshots and forward-only recordsets, but not dynasets. However, a Level 1 driver can support dynasets if it supports extended fetch and keyset-driven cursors.

In ODBC terminology, dynasets and snapshots are referred to as “cursors.” A cursor is a mechanism used for keeping track of its position in a recordset. For more information about driver requirements for dynasets, see the article Dynaset. For more information about cursors, see the ODBC SDK Programmer’s Reference on the MSDN Library CD.

Note For updatable recordsets, your ODBC driver must support either positioned update statements or the ::SQLSetPos ODBC API function. If both are supported, MFC uses ::SQLSetPos for efficiency. Alternatively, for snapshots, you can use the cursor library, which provides the required support for updatable snapshots (static cursors and positioned update statements).


Redistributing ODBC Components to Your Customers

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

If you incorporate the functionality of the ODBC Administrator programs into your application, you must also distribute to your users the files that run these programs. These ODBC files reside in the \OS\System directory of the Visual C++ CD-ROM. The REDISTRB.WRI file and the license agreement in the same directory contain a list of ODBC files that you may redistribute.

Consult the documentation for any ODBC drivers you plan to ship. You’ll need to determine which DLLs and other files to ship.

In addition, you need to include one other file in most cases. The ODBCCR32.DLL is the ODBC Cursor Library. This library gives Level 1 drivers the capability of forward and backward scrolling. It also provides the capability of supporting snapshots. For more information on the ODBC Cursor Library, see the article ODBC: The ODBC Cursor Library.

The following articles provide more information on using ODBC with the database classes:

  • ODBC: The ODBC Cursor Library

  • ODBC: Configuring an ODBC Data Source

  • ODBC: Calling ODBC API Functions Directly

See Also ODBC Administrator


ODBC: The ODBC Cursor Library

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes the ODBC Cursor Library and explains how to use it. Topics include:

  • The Cursor Library and Level 1 ODBC drivers

  • Positioned updates and timestamp columns

  • Using the Cursor Library

The ODBC Cursor Library is a dynamic-link library (DLL) that resides between the ODBC Driver Manager and the driver. In ODBC terms, a driver maintains a “cursor” to keep track of its position in the recordset. The cursor marks the position in the recordset to which you have already scrolled — the current record.

The Cursor Library and Level 1 ODBC Drivers

The ODBC Cursor Library gives Level 1 drivers the following new capabilities:

  • Forward and backward scrolling. Level 2 drivers don’t need the cursor library because they are already scrollable.

  • Support for snapshots. The cursor library manages a buffer containing the snapshot’s records. This buffer reflects your program’s deletions and edits to records but not the additions, deletions, or edits of other users, so the snapshot is only as current as the cursor library’s buffer. The buffer also does not reflect your own additions until you call Requery. Dynasets do not use the cursor library.

The cursor library will give you snapshots (static cursors) even if they are not normally supported by your driver. If your driver already supports static cursors, you don’t need to load the cursor library to get snapshot support. If you do use the cursor library, you can use only snapshots and forward-only recordsets. If your driver supports dynasets (KEYSET_DRIVEN cursors) and you want to use them, you must not use the cursor library. If you want to use both snapshots and dynasets, you must base them on two different CDatabase objects (two different connections) unless your driver supports both.

Positioned Updates and Timestamp Columns

Note ODBC data sources are accessible through the MFC ODBC classes, as described in this article, or through the MFC Data Access Object (DAO) classes. For information about the DAO classes, see the article DAO and MFC.

If your ODBC driver supports SQLSetPos, which MFC uses if available, this topic does not apply to you.

Most Level 1 drivers do not support positioned updates. Such drivers rely on the cursor library to emulate the capabilities of Level 2 drivers in this regard. The cursor library emulates positioned update support by doing a searched update on the unchanging fields.

In some cases, a recordset may contain a timestamp column as one of those unchanging fields. Two issues arise in using MFC recordsets with tables that contain timestamp columns.

The first issue concerns updatable snapshots on tables with timestamp columns. If the table to which your snapshot is bound contains a timestamp column, you should call Requery after you call Edit and Update. If not, you may not be able to edit the same record again. When you call Edit and then Update, the record is written to the data source and the timestamp column is updated. If you don’t call Requery, the timestamp value for the record in your snapshot no longer matches the corresponding timestamp on the data source. When you try to update the record again, the data source may disallow the update because of the mismatch.

The second issue concerns limitations of class CTime when used with the RFX_Date function to transfer time and date information to or from a table. Processing the CTime object imposes some overhead in the form of extra intermediate processing during the data transfer. The date range of CTime objects may also be too limiting for some applications. A new version of the RFX_Date function takes an ODBC TIMESTAMP_STRUCT parameter instead of a CTime object. For more information, see RFX_Date in Macros and Globals in the Class Library Reference.

Using the Cursor Library

When you connect to a data source — by calling CDatabase::OpenEx or CDatabase::Open — you can specify whether to use the cursor library for the data source. If you will be creating snapshots on that data source, specify the CDatabase::useCursorLib option in the dwOptions parameter to OpenEx, or specify TRUE for the bUseCursorLib parameter to Open (the default value is TRUE). If your ODBC driver supports dynasets and you want to open dynasets on the data source, do not use the cursor library (it masks some driver functionality needed for dynasets). In that case, do not specify CDatabase::useCursorLib in OpenEx, or specify FALSE for the bUseCursorLib parameter in Open.


ODBC: Configuring an ODBC Data Source

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

To use a data source with an application you’ve developed, you must use ODBC Administrator to configure it. ODBC Administrator keeps track of available data sources and their connection information in the Windows registry. Use ODBC Administrator to add, modify, and delete data sources in the Data Sources dialog box, and to add and delete ODBC drivers.

Note This information applies when you use MFC Data Access Object (DAO) classes for ODBC access as well as when you use MFC ODBC classes.

ODBC Administrator is automatically installed with the Microsoft Foundation Class Library database support. For more information about the ODBC Administrator program, see the article ODBC Administrator and the online ODBC API Reference help system.

Technical Note 48 describes how to write ODBC Setup and Administration programs for MFC database applications.

See Also ODBC: Calling ODBC API Functions Directly


ODBC: Calling ODBC API Functions Directly

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The database classes provide a simpler interface to a data source than does ODBC. As a result, the classes don’t encapsulate all of the ODBC API. For any functionality that falls outside the abilities of the classes, you must call ODBC API functions directly. For example, you must call the ODBC catalog functions (::SQLColumns, ::SQLProcedures, ::SQLTables, and others) directly. Samples of direct ODBC function calls used with the classes are in the MFC Database sample CATALOG.

Note ODBC data sources are accessible through the MFC ODBC classes, as described in this article, or through the MFC Data Access Object (DAO) classes. For information about the DAO classes, see the article DAO and MFC.

To call an ODBC API function directly, you must take the same steps you’d take if you were making the calls without the framework. They are:

  • Allocate storage for any results the call returns.

  • Pass an ODBC HDBC or HSTMT handle, depending on the parameter signature of the function.

    Member variables CDatabase::m_hdbc and CRecordset::m_hstmt are available so that you do not need to allocate and initialize these yourself.

  • Perhaps call additional ODBC functions to prepare for or follow up the main call.

  • Deallocate storage when you finish.

For more information about these steps, see the ODBC SDK Programmer’s Reference on the MSDN Library CD.

In addition to these steps, you need to take extra steps to check function return values, assure that your program isn’t waiting for an asynchronous call to finish, and so on. You can simplify these last steps by using the AFX_SQL_ASYNC and AFX_SQL_SYNC macros. See Macros and Globals in the Class Library Reference for information.

See Also ODBC


ODBC Administrator

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

ODBC Administrator registers and configures the data sources available to you either locally or across a network. ClassWizard uses information supplied by ODBC Administrator to create code in your applications that connects your users to data sources.

Note This information applies to ODBC data sources set up for use with either the MFC ODBC classes or the MFC Data Access Object (DAO) classes. To use an ODBC data source, you must first register and configure it.

You must use ODBC Administrator to add and remove data sources. Depending on the ODBC driver, you can also create new data sources.

During Setup, you select the ODBC drivers you want to install. You can later install additional drivers that ship with Visual C++ using the Visual C++ Setup program.

Note ODBC Administrator is installed during Setup. If you chose Custom Installation and did not select any ODBC drivers in the “Database Options” dialog box, you need to run Setup again to install the necessary files.

If you want to install ODBC drivers that do not ship with Visual C++, you must run the setup program that accompanies the driver.

To install ODBC drivers that ship with Visual C++

Note This procedure assumes that you have already installed VC++ and are rerunning Setup to add the ODBC drivers that ship with VC++.

  1. Run Setup from your Visual C++ distribution CD.

    This displays the opening dialog box in the Setup program.

  2. Click Next on each dialog box until you reach the Installation Options dialog box. Select the Custom radio button and click Next.

  3. Clear all of the check boxes on the Microsoft Visual C++ Setup dialog box except the Database Options check box. Click Details to display the Database Options dialog box.

  4. Clear the Microsoft Data Access Objects check box, select the Microsoft ODBC Drivers check box, and click Details.

    This displays the Microsoft ODBC Drivers dialog box.

  5. Select the drivers you want to install, then click OK twice.

  6. Click Next on the remaining dialog boxes to begin the installation. Setup notifies you when the installation is complete.

Once the drivers are installed, you can configure the data source using the ODBC Administrator. You will find the ODBC icon in the Control Panel. For information about configuring a data source with ODBC Administrator, see the ODBC SDK Programmer’s Reference on the MSDN Library CD.

See Also Data Source (ODBC)


ODBC Driver List

Home | Overview | How Do I | FAQ | Sample | Tutorial

Visual C++ provides ODBC drivers for the following databases:

  • SQL Server

  • Microsoft Access

  • Microsoft FoxPro

  • Microsoft Excel

  • dBASE

  • Paradox

  • Microsoft Oracle ODBC

  • Text files

For information about ODBC drivers available from Microsoft and other companies, including the ODBC Driver Pack, contact Microsoft Customer Service. Call the Microsoft Sales Information Team at 1-800-426-9400 and ask for Customer Service. Or call Visigenic Software, Inc., San Mateo, CA , at 1-415-286-1900 or 1-800-632-2864, for information about ODBC driver vendors. Outside the United States and Canada, please contact your local Microsoft Subsidiary.


Data Source (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For information about the MFC DAO classes, see the article Data Access Objects (DAO).

In database terms, a data source is a specific set of data, the information required to access that data, and the location of the data source, which can be described using a data-source name. To work with class CDatabase, the data source must be one that you have configured through Open Database Connectivity (ODBC) Administrator. Examples of data sources include a remote database running on Microsoft SQL Server across a network, or a Microsoft Access file in a local directory. From your application, you can access any data source for which you have an ODBC driver.

You can have one or more data sources active in your application at one time, each represented by a CDatabase object. You can also have multiple simultaneous connections to any data source. You can connect to remote as well as to local data sources, depending on the drivers you have installed and the capabilities of your ODBC drivers. For more information about data sources and ODBC Administrator, see the articles ODBC and ODBC Administrator.

The following articles explain more about data sources:

  • Data Source: Managing Connections (ODBC)

  • Data Source: Determining the Schema of the Data Source (ODBC)


Data Source: Managing Connections (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For information about the MFC DAO classes, see the article Data Access Objects (DAO).

This article explains:

  • How to configure a data source.

  • How a multiuser environment affects a data source and its recordsets.

  • Why you generalize a connection string to a data source.

  • How to connect to a data source.

  • How to disconnect from a data source.

  • How to reuse a CDatabase object.

Connecting to a data source means establishing communications with a DBMS in order to access the data. When you connect to a data source from an application through an ODBC driver, the driver makes the connection for you, either locally or across a network.

You can connect to any data source for which you have an ODBC driver. Users of your application must also have the same ODBC driver for their data source. For more information about redistributing ODBC drivers, see Redistributing ODBC Components to Your Customers in the article ODBC.

Configuring a Data Source

ODBC Administrator is used to configure your data sources. You can also use ODBC Administrator after installation to add or remove data sources. When you create applications, you can either direct your users to the ODBC Administrator to let them add data sources, or you can build this functionality into your application by making direct ODBC installation calls. For more information, see the Setup DLL Function Reference chapter in the ODBC Programmer’s Reference, the article ODBC Administrator, and the online ODBC API Reference help system.

Working in a Multiuser Environment

If multiple users are connected to a data source, they can change data while you are manipulating it in your recordsets. Similarly, your changes may affect other users’ recordsets. For more information about how your updates affect other users, and how their updates affect you, see the articles Recordset: How Recordsets Update Records (ODBC) and Transaction (ODBC).

Generalizing the Connection String

ClassWizard uses a default connection string to establish a connection to a data source. You use this connection to view tables and columns while you are developing your application. However, this default connection string may not be appropriate for your users’ connections to the data source through your application. For example, their data source and the path to its location may be different from the one used in developing your application. In that case, you should re-implement the CRecordset::GetDefaultConnect member function in a more generic fashion and discard ClassWizard’s implementation. For example, use one of the following approaches:

  • Register and manage the connect strings by using ODBC Administrator.

  • Remove the data-source name completely. The framework supplies “ODBC” as the data source and ODBC will display a dialog box asking for the data-source name, and any other required connection information.

  • Supply the data-source name only. ODBC will ask for the user ID and password, if required. For example, before generalizing, the connection string looks like this:
    CString CApp1Set::GetDefaultConnect()
{
return "ODBC;DSN=afx;UID=sa;PWD=Fred;";
}

    To generalize it, rewrite GetDefaultConnect so that it returns one of the following values:

    // Most general case. User must select data source and
// supply user and password
    return "ODBC;";
// User and password required
    return "ODBC;DSN=mydb;";
// Password required
    return "ODBC;DSN=mydb;UID=sa;";
// On most systems, will connect to server w/o any queries to user
    return "ODBC;DSN=mydb;UID=sa;PWD=Fred;";

Connecting to a Specific Data Source

To connect to a specific data source, your data source must already have been configured with ODBC Administrator.

To connect to a specific data source

  1. Construct a CDatabase object.

  2. Call its OpenEx or Open member function.

For more information about how to specify the data source if it is something other than the one you specified with ClassWizard, see CDatabase::OpenEx or CDatabase::Open in the Class Library Reference.

Disconnecting from a Data Source

You must close any open recordsets before calling the Close member function of CDatabase. In recordsets associated with the CDatabase object you want to close, any pending AddNew or Edit statements are canceled, and all pending transactions are rolled back.

To disconnect from a data source

  1. Call the CDatabase object’s Close member function.

  2. Destroy the object unless you want to reuse it.

Reusing a CDatabase Object

You can reuse a CDatabase object after disconnecting from it, whether you use it to reconnect to the same data source or to connect to a different data source.

To reuse a CDatabase object

  1. Close the object’s original connection.

  2. Instead of destroying the object, call its OpenEx or Open member function again.

See Also Data Source: Determining the Schema of the Data Source (ODBC) CRecordset


Data Source: Determining the Schema of the Data Source (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For information about the MFC DAO classes, see the article Data Access Objects (DAO).

To set up data members in your CRecordset objects, you need to know the schema of the data source to which you are connecting. Determining the schema of a data source involves obtaining a list of the tables in the data source, a list of the columns in each table, the data type of each column, and the existence of any indexes.

To determine the schema of a data source

  • See the MFC Database samples CATALOG and DYNABIND, which use the ODBC API functions ::SQLTables and ::SQLColumns.

See Also Data Source (ODBC), Data Source: Managing Connections (ODBC)


Data Source: Programmatically Configuring an ODBC Data Source

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how you can configure ODBC (Open Database Connectivity) data source names programmatically. This gives you flexibility to access data without forcing the user to explicitly use the ODBC Administrator or other programs to specify the names of data sources.

Typically, a user runs the ODBC Administrator program to create a data source, provided that the associated database management system (DBMS) supports this operation.

When creating a Microsoft Access ODBC data source through the ODBC Administrator program, you are given two choices: you can select an existing .MDB file or you can create a new .MDB file. There is no programmatic way of creating the .MDB file from your MFC ODBC application. Therefore, if your application requires that you place data into a Microsoft Access data source (.MDB file), you most likely will want to have an empty .MDB file that you can use or copy whenever you need it.

However, many DBMSs allow programmatic data source creation. Some data sources, such as FoxPro, maintain a directory specification for databases. That is, a directory is the data source and each table within the data source is stored in a separate file (in the case of dBASE or FoxPro, each table is a .DBF file). Drivers for other ODBC databases, such as Microsoft Access and SQL Server, require that some specific criteria be satisfied before a data source can be established. For example, when using the SQL Server ODBC driver you need to have established a SQL Server.

SQLConfigDataSource Example

The following example uses the ::SQLConfigDataSource ODBC API function to create a new Excel data source called “New Excel Data Source”:

SQLConfigDataSource(NULL,ODBC_ADD_DSN, "Excel Files (*.xls)",
                   "DSN=New Excel Data Source\0"
                   "Description=New Excel Data Source\0"
                   "FileType=Excel\0"
                   "DataDirectory=C:\\EXCELDIR\0"
                   "MaxScanRows=20\0");

Note that the data source is actually a directory (C:\EXCELDIR); this directory must exist. The Excel driver uses directories as its data sources, and files as the individual tables (one table per .XLS file).

For additional information on creating tables, see the article Data Source: Programmatically Creating a Table in an ODBC Data Source.

The information below discusses the parameters that need to be passed to the ::SQLConfigDataSource ODBC API function. To use ::SQLConfigDataSource, you must include the ODBCINST.H header file and use the ODBCINST.LIB import library. Also, ODBCCP32.DLL must be in the path at run time (or ODBCINST.DLL for 16 bit).

You can create an ODBC data source name using the ODBC Administrator program or a similar utility. However, sometimes it is desirable to create a data source name directly from your application to obtain access without requiring the user to run a separate utility.

The ODBC Administrator (typically installed in the Windows Control Panel) creates a new data source by putting entries in the Windows registry (or, for 16 bit, in the ODBC.INI file). The ODBC Driver Manager queries this file to obtain the required information about the data source. It’s important to know what information needs to be placed in the registry because you'll need to supply it with the call to ::SQLConfigDataSource.

Although this information could be written directly to the registry without using ::SQLConfigDataSource, any application that does so is relying on the current technique that the Driver Manager uses to maintain its data. If a later revision to the ODBC Driver Manager implements record keeping about data sources in a different way, then any application that uses this technique would be broken. It is generally advisable to use an API function when one is provided. For example, your code is portable from 16 bit to 32 bit if you use the ::SQLConfigDataSource function, as the function will correctly write to the ODBC.INI file or to the registry.

SQLConfigDataSource Parameters

The following explains the parameters of the ::SQLConfigDataSource function. Much of the information is taken from the ODBC API Programmer's Reference supplied with Visual C++ version 1.5 and later.

Function Prototype

BOOL SQLConfigDataSource(HWND hwndParent,UINT fRequest, LPCSTR lpszDriver, LPCSTR lpszAttributes);

Parameters and Usage

hwndParent The window specified as the owner of any dialog boxes that either the ODBC Driver Manager or the specific ODBC driver creates to obtain additional information from the user about the new data source. If the lpszAttributes parameter doesn’t supply enough information, a dialog box appears. The hwndParent parameter may be NULL; see the ODBC Programmer’s Reference for details.

lpszDriver The driver description. This is the name presented to users rather than the physical driver name (the DLL).

lpszAttributes List of attributes in the form “keyname=value”. These strings are separated by null terminators with two consecutive null terminators at the end of the list. These attributes are primarily default driver-specific entries, which go into the registry for the new data source. One important key that is not mentioned in the ODBC API reference for this function is “DSN” (“data source name”), which specifies the name of the new data source. The rest of the entries are specific to the driver for the new data source. Often it is not necessary to supply all of the entries because the driver can prompt the user with dialog boxes for the new values. (Set hwndParent to NULL to cause this.) You might want to explicitly supply default values so that the user is not prompted.

To determine the description of a driver for the lpszDriver parameter using the ODBC Administrator program

  1. Run the ODBC Administrator program.

  2. Choose Add.

This will give you a list of installed drivers and their descriptions. It is this description that you use as the lpszDriver parameter. Note that you use the entire description — for example, “Excel Files (*.xls)” — including the file extension and parentheses if they exist in the description.

As an alternative, you can examine the registry (or, for 16 bit, the file ODBCINST.INI), which contains a list of all driver entries and descriptions under the registry key “ODBC Drivers” (or the section [ODBC Drivers] in ODBCINST.INI).

One way to find the keynames and values for the lpszAttributes parameter is to examine the ODBC.INI file for an already configured data source (perhaps one that has been configured by the ODBC Administrator program):

To find keynames and values for the lpszAttributes parameter

  1. Run the Windows registry editor (or, for 16 bit, open the ODBC.INI file).

  2. Find the ODBC data sources information using one of the following.
    • For 32 bit, find the key HKEY_CURRENT_USER\Software\ODBC\ODBC.INI\ODBC Data Sources in the left-hand pane.

      The right-hand pane lists entries of the form: “pub: REG_SZ:<data source name>”, where <data source name> is a data source that has already been configured with the desired settings for the driver you intend to use. Select the data source you want, for example, SQL Server. The items following the string “pub:” are, in order, the keyname and value to use in your lpszAttributes parameter.

    • For 16 bit, find the section in the ODBC.INI file marked by [<data source name>].

      The lines following this line will be of the form “keyname=value”. These are exactly the entries to use in your lpszAttributes parameter.

You might also want to examine the documentation for the specific driver you are going to use. You can find useful information in the online help for the driver, which you can access by running the ODBC Administrator. These help files are usually placed in the WINDOWS\SYSTEM directory for Windows NT, Windows 3.1, or Windows 95.

To obtain online help for your ODBC driver

  1. Run ODBC Administrator.

  2. Choose Add.

  3. Select the driver name.

  4. Choose OK.

When ODBC Administrator displays the information for creating a new data source for that particular driver, select Help. This opens the help file for that particular driver, which generally contains important information concerning the use of the driver.

For related information, see the Installer DLL Function Reference in the ODBC SDK on the MSDN Library CD.


Data Source: Programmatically Creating a Table in an ODBC Data Source

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to create a table for your data source, using the ExecuteSQL member function of class CDatabase, passing the function a string that contains a CREATE TABLE SQL statement.

For general information about ODBC data sources in MFC, see the article Data Source (ODBC). The article Data Source: Programmatically Configuring an ODBC Data Source describes creating data sources.

Once you have the data source established, you can easily create tables using the ExecuteSQL member function and the CREATE TABLE SQL statement. For example, if you had a CDatabase object called myDB, you could use the following MFC code to create a table:

myDB.ExecuteSQL("CREATE TABLE OFFICES (OfficeID TEXT(4)" ",
                         OfficeName TEXT(10))");

The code above creates a table called “OFFICES” in the Microsoft Access data source connection maintained by myDB; the table contains two fields “OfficeID” and “OfficeName.” For more information about creating tables as well as primary keys and indexes for them, see Appendix C in the ODBC Programmer’s Reference.

Note The field types specified in the CREATE TABLE SQL statement may vary according to the ODBC driver that you are using. The Microsoft Query program (distributed with Visual C++ 1.5) is one way to discover what field types are available for a data source. In MS Query, select File, choose Table_Definition, select a table from a data source, and look at the type shown in the “Type” combo box. Appendix C in the ODBC Programmer’s Reference describes the supported SQL syntax. SQL syntax also exists to create indexes. The Programmer’s Reference is in the ODBC SDK on the MSDN Library CD.


Dynaset

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article describes dynasets and discusses their availability.

Note This article applies to the MFC ODBC classes, including CRecordset. For information about dynasets in the DAO classes, see class CDaoRecordset. With DAO, you can open dynaset-type recordsets.

A “dynaset” is a recordset with dynamic properties. During its lifetime, a recordset object in dynaset mode (usually called simply a “dynaset”) stays synchronized with the data source in the following way. In a multiuser environment, other users may edit or delete records that are in your dynaset or add records to the table your dynaset represents. Records your application adds to or deletes from the recordset are reflected in your dynaset. Records that other users add to the table will not be reflected in your dynaset until you rebuild the dynaset by calling its Requery member function. When other users delete records, MFC code skips over the deletions in your recordset. Other users’ editing changes to existing records are reflected in your dynaset as soon as you scroll to the affected record.

Similarly, edits you make to records in a dynaset are reflected in dynasets in use by other users. Records you add are not reflected in other users’ dynasets until they requery their dynasets. Records you delete are marked as “deleted” in other users’ recordsets. If you have multiple connections to the same database (multiple CDatabase objects), recordsets associated with those connections have the same status as the recordsets of other users.

Dynasets are most valuable when data must be dynamic, as, for example, in an airline reservation system.

Important To use dynasets, you must have an ODBC driver for your data source that supports dynasets, and the ODBC cursor library must not be loaded. See Availability of Dynasets.

To specify that a recordset is a dynaset, pass CRecordset::dynaset as the first parameter to the Open member function of your recordset object.

Note For updatable dynasets, your ODBC driver must support either positioned update statements or the ::SQLSetPos ODBC API function. If both are supported, MFC uses ::SQLSetPos for efficiency.

Availability of Dynasets

The MFC database classes support dynasets if the following requirements are met:

  • The ODBC cursor library DLL must not be in use for this data source.

    If the cursor library is used, it masks some functionality of the underlying ODBC driver that is necessary for dynaset support. If you want to use dynasets (and your ODBC driver has the functionality required for dynasets, as described in the rest of this section), you can cause MFC not to load the cursor library when you create a CDatabase object. For more information, see the article ODBC and the OpenEx or Open member function of class CDatabase.

    In ODBC terminology, dynasets and snapshots are referred to as “cursors.” A cursor is a mechanism used for keeping track of its position in a recordset. For more information about cursors, see the ODBC SDK Programmer’s Reference on the MSDN Library CD.

  • The ODBC driver for your data source must support keyset-driven cursors.

    Keyset-driven cursors manage data from a table by getting and storing a set of keys. The keys are used to obtain current data from the table when the user scrolls onto a particular record. To determine whether your driver provides this support, call the ::SQLGetInfo ODBC API function with the SQL_SCROLL_OPTIONS parameter.

    If you try to open a dynaset without keyset support, you get a CDBException with the return code value AFX_SQL_ERROR_DYNASET_NOT_SUPPORTED.

  • The ODBC driver for your data source must support extended fetching.

    “Extended fetching” is the ability to scroll backward as well as forward over the resulting records of your SQL query. To determine whether your driver supports this ability, call the ::SQLGetFunctions ODBC API function with the SQL_API_SQLEXTENDEDFETCH parameter.

If you want updatable dynasets (or snapshots, for that matter), your ODBC driver must also support either the ::SQLSetPos ODBC API function or positioned updates. The ::SQLSetPos function allows MFC to update the data source without sending SQL statements. If this support is available, MFC uses it in preference to making updates via SQL. To determine whether your driver supports ::SQLSetPos, call ::SQLGetInfo with the SQL_POS_OPERATIONS parameter.

Positioned updates use SQL syntax (of the form WHERE CURRENT OF <cursorname>) to identify a particular row in the table on the data source. To determine whether your driver supports positioned updates, call ::SQLGetInfo with the SQL_POSITIONED_STATEMENTS parameter.

Generally, MFC dynasets (but not forward-only recordsets) require an ODBC driver with level 2 API conformance. If the driver for your data source conforms to the level 1 API set, you can still use both updatable and read-only snapshots and forward-only recordsets, but not dynasets. However, a level 1 driver can support dynasets if it supports extended fetching and keyset-driven cursors. For more information about ODBC conformance levels, see the article ODBC.

Note If you want to use both snapshots and dynasets, you must base them on two different CDatabase objects (two different connections).

Unlike snapshots, which use intermediate storage maintained by the ODBC cursor library, dynasets fetch a record directly from the data source as soon as you scroll to it. This keeps the records originally selected by the dynaset synchronized with the data source.

See the article ODBC Driver List for a list of ODBC drivers included in this version of Visual C++ and for information about obtaining additional drivers.


Snapshot

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

A snapshot is a recordset that reflects a static view of the data as it existed at the time the snapshot was created. Once you open the snapshot and move to all the records, the set of records it contains and their values don’t change until you rebuild the snapshot by calling Requery.

Note This article applies to the MFC ODBC classes. If you’re using the MFC DAO classes instead of the MFC ODBC classes, see CDaoRecordset::Open for a description of snapshot-type recordsets. Also see the article DAO Recordset: Creating Recordsets.

You can create updatable or read-only snapshots with the database classes. Unlike a dynaset, an updatable snapshot doesn’t reflect changes to record values made by other users, but does reflect updates and deletions made by your program. Records added to a snapshot don’t become visible to the snapshot until you call Requery.

Tip A snapshot is an ODBC “static cursor.” Static cursors don’t actually get a row of data until you scroll to that record. To ensure that all records are immediately retrieved, you can scroll to the end of your recordset, then scroll to the first record you’re interested in. Note, however, that scrolling to the end entails extra overhead and can lower performance.

Snapshots are most valuable when you need the data to remain fixed during your operations, as when you’re generating a report or performing calculations. Even so, the data source can diverge considerably from your snapshot, so you may want to rebuild it from time to time.

Snapshot support is based on the ODBC Cursor Library, which provides static cursors and positioned updates (needed for updatability) for any Level 1 driver. The cursor library DLL must be loaded in memory for this support. When you construct a CDatabase object and call its OpenEx member function, you must specify the CDatabase::useCursorLib option of the dwOptions parameter. If you call the Open member function, then the cursor library is loaded by default. Note that if you are using dynasets instead of snapshots, you do not want to cause the cursor library to be loaded.

Snapshots are available only if the ODBC Cursor Library was loaded when the CDatabase object was constructed or the ODBC driver you’re using supports static cursors.

Important For some ODBC drivers, snapshots (static cursors) may not be updatable. Check your driver documentation for cursor types supported and the concurrency types they support. To guarantee updatable snapshots, make sure you load the cursor library into memory when you create a CDatabase object. See the article ODBC: The ODBC Cursor Library.

Note If you want to use both snapshots and dynasets, you must base them on two different CDatabase objects (two different connections).

For more information about the properties snapshots share with all recordsets, see the article Recordset (ODBC). For more information about ODBC and snapshots, including the ODBC Cursor Library, see the article ODBC.


Record Field Exchange (RFX)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

The MFC ODBC database classes automate moving data between the data source and a recordset object. When you derive a class from CRecordset and do not use bulk row fetching, data is transferred via the record field exchange (RFX) mechanism.

Note If you have implemented bulk row fetching in a derived CRecordset class, then the framework uses the bulk record field exchange (Bulk RFX) mechanism to transfer data. For more information, see the article Recordset: Fetching Records in Bulk (ODBC).

RFX is similar to dialog data exchange (DDX). Moving data between a data source and the field data members of a recordset requires multiple calls to the recordset’s DoFieldExchange function and considerable interaction between the framework and ODBC. The RFX mechanism is type-safe and saves you the work of calling ODBC functions such as ::SQLBindCol. (For more information about DDX, see Dialog Data Exchange and Validation.)

RFX is mostly transparent to you. If you declare your recordset classes with AppWizard or ClassWizard, RFX is built into them automatically. Your recordset class must be derived from the base class CRecordset supplied by the framework. AppWizard lets you create an initial recordset class. ClassWizard lets you add other recordset classes as you need them. You use ClassWizard to map recordset field data members to table columns on the data source. For more information and examples, see the article ClassWizard: Creating a Recordset Class.

You must manually add a small amount of RFX code in three cases — when you want to:

  • Use parameterized queries. See the article Recordset: Parameterizing a Recordset (ODBC).

  • Perform joins — using one recordset for columns from two or more tables. See the article Recordset: Performing a Join (ODBC).

  • Bind data columns dynamically. This is less common than parameterization. See the article Recordset: Dynamically Binding Data Columns (ODBC).

If you need a more advanced understanding of RFX, see the article Record Field Exchange: How RFX Works.

The following articles explain the details of using recordset objects:

  • Record Field Exchange: Using RFX

  • Record Field Exchange: Using the RFX Functions

  • Record Field Exchange: How RFX Works

See Also Recordset (ODBC), ClassWizard: Creating a Recordset Class, Overview: Creating a Program That Supports a Database, CRecordset


Record Field Exchange: Using RFX

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains what you do to use RFX in relation to what the framework does.

Note This article applies to classes derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, then bulk record field exchange (Bulk RFX) is implemented. Bulk RFX is similar to RFX. To understand the differences, see the article Recordset: Fetching Records in Bulk (ODBC).

The following articles contain related information:

  • Record Field Exchange: Working with the Wizard Code introduces the main components of RFX and explains the code that AppWizard and ClassWizard write to support RFX and how you might want to modify the wizard code.

  • Record Field Exchange: Using the RFX Functions explains writing calls to the RFX functions in your DoFieldExchange override.

The following table shows your role in relation to what the framework does for you.

Using RFX: You and the Framework

You... | The framework...
Declare your recordset classes with ClassWizard. Specify names and data types of field data members. | ClassWizard derives a CRecordset class and writes a DoFieldExchange override for you, including an RFX function call for each field data member.
(Optional) Manually add any needed parameter data members to the class. Manually add an RFX function call to DoFieldExchange for each parameter data member, add a call to CFieldExchange::SetFieldType for the group of parameters, and specify the total number of parameters in m_nParams. See Recordset: Parameterizing a Recordset (ODBC). |
(Optional) Manually bind additional columns to field data members. Manually increment m_nFields. See Recordset: Dynamically Binding Data Columns (ODBC). |
Construct an object of your recordset class. Before using the object, set the values of its parameter data members, if any. | For efficiency, the framework prebinds the parameters, using ODBC. When you pass parameter values, the framework passes them to the data source. Only the parameter values are sent for requeries, unless the sort and/or filter strings have changed.
Open a recordset object using CRecordset::Open. | Executes the recordset’s query, binds columns to field data members of the recordset, and calls DoFieldExchange to exchange data between the first selected record and the recordset’s field data members.
Scroll in the recordset using CRecordset::Move or a menu or toolbar command. | Calls DoFieldExchange to transfer data to the field data members from the new current record.
Add, update, and delete records. | Calls DoFieldExchange to transfer data to the data source.

See Also Record Field Exchange: How RFX Works, Recordset: Obtaining SUMs and Other Aggregate Results (ODBC), CRecordset, CFieldExchange, Macros and Globals


Record Field Exchange: Working with the Wizard Code

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the code that AppWizard and ClassWizard write to support RFX and how you might want to alter that code.

Note This article applies to classes derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, then bulk record field exchange (Bulk RFX) is implemented. Bulk RFX is similar to RFX. To understand the differences, see the article Recordset: Fetching Records in Bulk (ODBC).

When you create a recordset class with ClassWizard (or with AppWizard), the wizard writes the following RFX-related elements for you, based on the data source, table, and column choices you make in the wizard:

  • Declarations of the recordset field data members in the recordset class.

  • An override of CRecordset::DoFieldExchange.

  • Initialization of recordset field data members in the recordset class constructor.

The Field Data Member Declarations

The wizards write a recordset class declaration in an .H file that resembles the following for class CSections:

class CSections : public CRecordset
{
public:
    CSections(CDatabase* pDatabase);
    CSections::~CSections();

// Field/Param Data
    //{{AFX_FIELD(CSections, CRecordset)
    CString   m_strCourseID;
    CString   m_strInstructorID;
    CString   m_strRoomNo;
    CString   m_strSchedule;
    CString   m_strSectionNo;
    //}}AFX_FIELD

// Implementation
protected:
    virtual CString GetDefaultConnect();   // Default connection string
    virtual CString GetDefaultSQL();    // Default SQL for Recordset
    virtual void DoFieldExchange(CFieldExchange* pFX);  // RFX support
    DECLARE_DYNAMIC(CSections)
};

Notice the following key features about the class above:

  • Special “//{{AFX_FIELD” comments that bracket the field data member declarations. ClassWizard uses these to update your source file.

  • The wizard overrides the DoFieldExchange member function of class CRecordset.

Caution Never edit the code inside “//{{AFX” brackets. Always use ClassWizard. If you add parameter data members or new field data members that you bind yourself, add them outside the brackets.

The DoFieldExchange Override

DoFieldExchange is the heart of RFX. The framework calls DoFieldExchange any time it needs to move data either from data source to recordset or from recordset to data source. DoFieldExchange also supports obtaining information about field data members through the IsFieldDirty and IsFieldNull member functions.

The following DoFieldExchange override is for the CSections class. ClassWizard writes the function in the .CPP file for your recordset class.

void CSections::DoFieldExchange(CFieldExchange* pFX)
{
    //{{AFX_FIELD_MAP(CSections)
    pFX->SetFieldType(CFieldExchange::outputColumn);
    RFX_Text(pFX, "CourseID", m_strCourseID);
    RFX_Text(pFX, "InstructorID", m_strInstructorID);
    RFX_Text(pFX, "RoomNo", m_strRoomNo);
    RFX_Text(pFX, "Schedule", m_strSchedule);
    RFX_Text(pFX, "SectionNo", m_strSectionNo);
    //}}AFX_FIELD_MAP
}

Notice the following key features of the function:

  • The special “//{{AFX_FIELD_MAP” comments. ClassWizard uses these to update your source file. This section of the function is called the “field map.”

  • A call to CFieldExchange::SetFieldType, through the pFX pointer. This call specifies that all RFX function calls up to the end of DoFieldExchange or the next call to SetFieldType are “output columns.” See CFieldExchange::SetFieldType for more information.

  • Several calls to the RFX_Text global function — one per field data member (all of which are CString variables in the example). These calls specify the relationship between a column name on the data source and a field data member. The RFX functions do the actual data transfer. The class library supplies RFX functions for all of the common data types. For more information about RFX functions, see the article Record Field Exchange: Using the RFX Functions.

    Note The order of the columns in your result set must match the order of the RFX function calls in DoFieldExchange.

  • The pFX pointer to a CFieldExchange object that the framework passes when it calls DoFieldExchange. The CFieldExchange object specifies the operation that DoFieldExchange is to perform, the direction of transfer, and other context information.

The Recordset Constructor

The recordset constructor that the wizards write contains two things related to RFX:

  • An initialization for each field data member.

  • An initialization for the m_nFields data member, which contains the number of field data members.

The constructor for the CSections recordset example looks like this:

CSections::CSections(CDatabase* pdb)
    : CRecordset(pdb)
{
    //{{AFX_FIELD_INIT(CSections)
    m_strCourseID = "";
    m_strInstructorID = "";
    m_strRoomNo = "";
    m_strSchedule = "";
    m_strSectionNo = "";
    m_nFields = 5;
    //}}AFX_FIELD_INIT
}

Important If you add any field data members manually, as you might if you bind new columns dynamically, you must increment m_nFields. Do so with another line of code outside the “//{{AFX_FIELD_INIT” brackets:

    m_nFields += 3;

This is the code for adding three new fields. If you add any parameter data members, you must initialize the m_nParams data member, which contains the number of parameter data members. Put the m_nParams initialization outside the brackets.


Record Field Exchange: Using the RFX Functions

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to use the RFX function calls that make up the body of your DoFieldExchange override.

Note This article applies to classes derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, then bulk record field exchange (Bulk RFX) is implemented. Bulk RFX is similar to RFX. To understand the differences, see the article Recordset: Fetching Records in Bulk (ODBC).

The RFX global functions exchange data between columns on the data source and field data members in your recordset. Normally you use ClassWizard to write the RFX function calls in your recordset’s DoFieldExchange member function. This article describes the functions briefly and shows the data types for which RFX functions are available. Technical Note 43 describes how to write your own RFX functions for additional data types.

RFX Function Syntax

Each RFX function takes three parameters (and some take an optional fourth or fifth parameter):

  • A pointer to a CFieldExchange object. You simply pass along the pFX pointer passed to DoFieldExchange.

  • The name of the column as it appears on the data source.

  • The name of the corresponding field data member or parameter data member in the recordset class.

  • (Optional) In some of the functions, the maximum length of the string or array being transferred. This defaults to 255 bytes, but you might want to change it. The maximum size is based on the maximum size of a CString object — INT_MAX (2,147,483,647) bytes — but you will probably encounter driver limits before that size.

  • (Optional) In the RFX_Text function, you sometimes use a fifth parameter to specify the data type of a column.

For more information, see the RFX functions under Macros and Globals in the Class Library Reference. For an example of when you might make special use of the parameters, see the article Recordset: Obtaining SUMs and Other Aggregate Results (ODBC).

RFX Data Types

The class library supplies RFX functions for transferring many different data types between the data source and your recordsets. The following list summarizes the RFX functions by data type. In cases where you must write your own RFX function calls, select from these functions by data type.

Function | Data Type
RFX_Bool | BOOL
RFX_Byte | BYTE
RFX_Binary | CByteArray
RFX_Double | double
RFX_Single | float
RFX_Int | int
RFX_Long | long
RFX_LongBinary | CLongBinary
RFX_Text | CString
RFX_Date | CTime

For more information, see the RFX function documentation under Macros and Globals in the Class Library Reference. For information about how C++ data types map to SQL data types, see the table ANSI SQL Data Types Mapped to C++ Data Types in the article SQL: SQL and C++ Data Types (ODBC).

See Also Record Field Exchange: How RFX Works, Recordset: Parameterizing a Recordset (ODBC), Recordset: Dynamically Binding Data Columns (ODBC), CRecordset, CFieldExchange


Record Field Exchange: How RFX Works

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains the RFX process. This is an advanced topic covering:

  • RFX and the recordset

  • The RFX process

Note This article applies to classes derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, then bulk record field exchange (Bulk RFX) is implemented. Bulk RFX is similar to RFX. To understand the differences, see the article Recordset: Fetching Records in Bulk (ODBC).

RFX and the Recordset

The recordset object’s field data members, taken together, constitute an “edit buffer” that holds the selected columns of one record. When the recordset is first opened and is about to read the first record, RFX binds (associates) each selected column to the address of the appropriate field data member. When the recordset updates a record, RFX calls ODBC API functions to send an SQL UPDATE or INSERT statement to the driver. RFX uses its knowledge of the field data members to specify the columns to write.

The framework backs up the edit buffer at certain stages so it can restore its contents if necessary. RFX backs up the edit buffer before adding a new record and before editing an existing record. It restores the edit buffer in some cases, for example, after an Update call following AddNew. The edit buffer is not restored if you abandon a newly changed edit buffer by, for example, moving to another record before calling Update.

Besides exchanging data between the data source and the recordset’s field data members, RFX manages binding parameters. When the recordset is opened, any parameter data members are bound in the order of the “?” placeholders in the SQL statement that CRecordset::Open constructs. For more information, see the article Recordset: Parameterizing a Recordset (ODBC).

Your recordset class’s override of DoFieldExchange does all the work, moving data in both directions. Like dialog data exchange (DDX), RFX needs information about the data members of your class. ClassWizard provides the necessary information by writing a recordset-specific implementation of DoFieldExchange for you, based on the field data member names and data types you specify with the wizard.

The Record Field Exchange Process

This section describes the sequence of RFX events as a recordset object is opened and as you add, update, and delete records. The table Using RFX: You and the Framework in the article Record Field Exchange: Using RFX shows the process at a high level, illustrating operations as a recordset is opened. The table Sequence of RFX Operations During Recordset Open and the table Sequence of RFX Operations During Scrolling in this article show the process as RFX processes a Move command in the recordset and as RFX manages an update. During these processes, DoFieldExchange is called to perform many different operations. The m_nOperation data member of the CFieldExchange object determines which operation is requested. You might find it helpful to read the articles Recordset: How Recordsets Select Records (ODBC) and Recordset: How Recordsets Update Records (ODBC) before you read this material.

RFX: Initial Binding of Columns and Parameters

The following RFX activities occur, in the order shown, when you call a recordset object’s Open member function:

  • If the recordset has parameter data members, the framework calls DoFieldExchange to bind the parameters to parameter placeholders in the recordset’s SQL statement string. A data type-dependent representation of the value of the parameter is used for each placeholder found in the SELECT statement. This occurs after the SQL statement is prepared but before it is executed. (For information about statement preparation, see the ::SQLPrepare function in the ODBC Programmer’s Reference.)

  • The framework calls DoFieldExchange a second time to bind the values of selected columns to corresponding field data members in the recordset. This establishes the recordset object as an edit buffer containing the columns of the first record.

  • The recordset executes the SQL statement and the data source selects the first record. The record’s columns are loaded into the recordset’s field data members.

The following table shows the sequence of RFX operations when you open a recordset.

Sequence of RFX Operations During Recordset Open

Your operation | DoFieldExchange operation | Database/SQL operation
1. Open recordset. |  |
 | 2. Build an SQL statement. |
 |  | 3. Send the SQL.
 | 4. Bind parameter data member(s). |
 | 5. Bind field data member(s) to column(s). |
 |  | 6. ODBC does the move and fills in the data.
 | 7. Fix up the data for C++. |

Recordsets use ODBC’s “prepared execution” to allow for fast requerying with the same SQL statement. For more information about prepared execution, see the ODBC SDK Programmer’s Reference on the MSDN Library CD.

RFX: Scrolling

When you scroll from one record to another, the framework calls DoFieldExchange to replace the values previously stored in the field data members with values for the new record.

The following table shows the sequence of RFX operations when the user moves from record to record.

Sequence of RFX Operations During Scrolling

Your operation | DoFieldExchange operation | Database/SQL operation
1. Call MoveNext or one of the other Move functions. |  |
 |  | 2. ODBC does the move and fills in the data.
 | 3. Fix up the data for C++. |

RFX: Adding New Records and Editing Existing Records

If you add a new record, the recordset operates as an edit buffer to build up the contents of the new record. As with adding records, editing records involves changing the values of the recordset’s field data members. From the RFX perspective, the sequence is as follows:

  1. Your call to the recordset’s AddNew or Edit member function causes RFX to store the current edit buffer so it can be restored later.

  2. AddNew or Edit prepares the fields in the edit buffer so RFX can detect changed field data members.

    Since a new record has no previous values to compare new ones with, AddNew sets the value of each field data member to a PSEUDO_NULL value. Later, when you call Update, RFX compares each data member’s value with the PSEUDO_NULL value. If there is a difference, the data member has been set. (PSEUDO_NULL is not the same thing as a record column with a true Null value, nor is either of these the same as C++ NULL.)

    Unlike the Update call for AddNew, the Update call for Edit compares updated values with previously stored values rather than using PSEUDO_NULL. The difference is that AddNew has no previously stored values for comparison.

  3. You directly set the values of field data members whose values you want to edit or that you want filled for a new record. (This can include calling SetFieldNull.)

  4. Your call to Update checks for changed field data members, as described in step 2 (see the table Sequence of RFX Operations During Scrolling). If none have changed, Update returns 0. If some field data members have changed, Update prepares and executes an SQL INSERT statement that contains values for all updated fields in the record.

  5. For AddNew, Update concludes by restoring the previously stored values of the record that was current before the AddNew call. For Edit, the new, edited values remain in place.

The following table shows the sequence of RFX operations when you add a new record or edit an existing record.

Sequence of RFX Operations During AddNew and Edit

Your operation | DoFieldExchange operation | Database/SQL operation
1. Call AddNew or Edit. |  |
 | 2. Back up the edit buffer. |
 | 3. For AddNew, mark field data members as “clean” and Null. |
4. Assign values to recordset field data members. |  |
5. Call Update. |  |
 | 6. Check for changed fields. |
 | 7. Build SQL INSERT statement for AddNew or UPDATE statement for Edit. |
 |  | 8. Send the SQL.
 | 9. For AddNew, restore the edit buffer to its backed-up contents. For Edit, delete the backup. |

RFX: Deleting Existing Records

When you delete a record, RFX sets all the fields to NULL as a reminder that the record is deleted and you must move off it. You won’t need any other RFX sequence information.

See Also ClassWizard: Creating a Recordset Class, Macros and Globals, CFieldExchange, CRecordset::DoFieldExchange


Recordset (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

A CRecordset object represents a set of records selected from a data source. The records can be from:

  • A table

  • A query

  • A stored procedure that accesses one or more tables

An example of a recordset based on a table is “all customers,” which accesses a Customer table. An example of a query is “all invoices for Joe Smith.” An example of a recordset based on a stored procedure (sometimes called a predefined query) is “all of the delinquent accounts,” which invokes a stored procedure in the back-end database. A recordset can join two or more tables from the same data source, but not from different data sources.

Note Some ODBC drivers support views of the database. A view in this sense is a query originally created with the SQL CREATE VIEW statement. The wizards currently do not support views, but it is possible to code this support yourself.

Recordset Capabilities

All recordset objects share the following capabilities:

  • If the data source is not read-only, you can specify that your recordset be updatable, appendable, or read-only. If the recordset is updatable, you can choose either pessimistic or optimistic locking methods, provided the driver supplies the appropriate locking support. If the data source is read-only, the recordset will be read-only.

  • You can call member functions to scroll through the selected records.

  • You can filter the records to constrain which records are selected from those available.

  • You can sort the records in ascending or descending order, based on one or more columns.

  • You can parameterize the recordset in order to qualify the recordset selection at run time.

Snapshots and Dynasets

There are two principal kinds of recordsets: snapshots and dynasets. Both are supported by class CRecordset. Each shares the common characteristics of all recordsets, but each also extends the common functionality in its own specialized way. Snapshots provide a static view of the data and are useful for reports and other situations in which you want a view of the data as it existed at a particular time. Dynasets are useful when you want updates made by other users to be visible in the recordset without having to requery or refresh the recordset. Snapshots and dynasets can be updatable or read-only. In order to reflect records added or deleted by other users, call CRecordset::Requery.

CRecordset also allows for two other kinds of recordsets: dynamic recordsets and forward-only recordsets. Dynamic recordsets are similar to dynasets; however, dynamic recordsets reflect any records added or deleted without calling CRecordset::Requery. For this reason, dynamic recordsets are generally expensive with respect to processing time on the DBMS, and many ODBC drivers do not support them. In contrast, forward-only recordsets provide the most efficient method of data access for recordsets that don't require updates or backward scrolling. For example, you might use a forward-only recordset to migrate data from one data source to another, where you only need to move through the data in a forward direction. To use a forward-only recordset, you must do both of the following:

  • Pass the option CRecordset::forwardOnly as the nOpenType parameter of the Open member function.

  • Specify CRecordset::readOnly in the dwOptions parameter of Open.

Important For information about ODBC driver requirements for dynaset support, see the article ODBC. For a list of ODBC drivers included in this version of Visual C++ and for information about obtaining additional drivers, see the article ODBC Driver List.

Your Recordsets

For every distinct table, view, or stored procedure you wish to access, you typically define a class derived from CRecordset, normally with the help of ClassWizard. (The exception is a database join, in which one recordset represents columns from two or more tables.) When you derive a recordset class with ClassWizard, you enable the record field exchange (RFX) mechanism or the bulk record field exchange (Bulk RFX) mechanism, which are similar to the dialog data exchange (DDX) mechanism. RFX and Bulk RFX simplify the transfer of data from the data source into your recordset; RFX additionally transfers data from your recordset to the data source. For more information, see the articles Record Field Exchange (RFX) and Recordset: Fetching Records in Bulk (ODBC).

A recordset object gives you access to all the selected records. You scroll through the multiple selected records using CRecordset member functions, such as MoveNext and MovePrev. At the same time, a recordset object represents only one of the selected records, the “current record.” You can examine the fields of the current record by declaring recordset class member variables that correspond to columns of the table or of the records that result from the database query. ClassWizard helps you declare these recordset class data members. You update a record by scrolling to it — making it the current record — and changing the values of these data members. For details about recordset data members, see the article Recordset: Architecture (ODBC).

The articles listed below explain the details of using recordset objects. The articles are listed in functional categories and a natural browse order to permit sequential reading.

Articles about the mechanics of opening, reading, and closing recordsets

  • Recordset: Architecture (ODBC)

  • Recordset: Declaring a Class for a Table (ODBC)

  • Recordset: Creating and Closing Recordsets (ODBC)

  • Recordset: Scrolling (ODBC)

  • Recordset: Bookmarks and Absolute Positions (ODBC)

  • Recordset: Filtering Records (ODBC)

  • Recordset: Sorting Records (ODBC)

  • Recordset: Parameterizing a Recordset (ODBC)

Articles about the mechanics of modifying recordsets

  • Recordset: Adding, Updating, and Deleting Records (ODBC)

  • Recordset: Locking Records (ODBC)

  • Recordset: Requerying a Recordset (ODBC)

Articles about somewhat more advanced techniques

  • Recordset: Performing a Join (ODBC)

  • Recordset: Declaring a Class for a Predefined Query (ODBC)

  • Recordset: Dynamically Binding Data Columns (ODBC)

  • Recordset: Fetching Records in Bulk (ODBC)

  • Recordset: Working with Large Data Items (ODBC)

  • Recordset: Obtaining SUMs and Other Aggregate Results (ODBC)

Articles about how recordsets work

  • Recordset: How Recordsets Select Records (ODBC)

  • Recordset: How Recordsets Update Records (ODBC)

See Also ClassWizard: Creating a Recordset Class, Transaction (ODBC)


Recordset: Architecture (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article describes the data members that comprise the architecture of a recordset object:

  • Field data members

  • Parameter data members

  • Using m_nFields and m_nParams data members

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If bulk row fetching is implemented, the architecture is similar. To understand the differences, see the article Recordset: Fetching Records in Bulk (ODBC).

A Sample Class

When you use ClassWizard to declare a recordset class derived from CRecordset, the resulting class has the general structure shown in the following simple class:

class CCourse : CRecordset
{
   //{{AFX_FIELD(CCourse, CRecordset)
   CString m_strCourseID;
   CString m_strCourseTitle;
   //}}AFX_FIELD
   CString m_strIDParam;
};

At the beginning of the class, ClassWizard writes a set of field data members. When you create the class with ClassWizard, you must specify one or more field data members. If the class is parameterized, as the sample class is (with the data member m_strIDParam), you must manually add parameter data members. ClassWizard doesn’t support adding parameters to a class.

Field Data Members

The most important members of your recordset class are the field data members. For each column you select from the data source, the class contains a data member of the appropriate data type for that column. For example, the sample class shown at the beginning of this article has two field data members, both of type CString, called m_strCourseID and m_strCourseTitle.

When the recordset selects a set of records, the framework automatically “binds” the columns of the current record (after the Open call, the first record is current) to the field data members of the object. That is, the framework uses the appropriate field data member as a buffer in which to store the contents of a record column.

As the user scrolls to a new record, the framework uses the field data members to represent the current record. The framework refreshes the field data members, replacing the previous record’s values. The field data members are also used for updating the current record and for adding new records. As part of the process of updating a record, you specify the update values by assigning values directly to the appropriate field data member(s).

Parameter Data Members

If the class is “parameterized,” it has one or more parameter data members. A parameterized class lets you base a recordset query on information obtained or calculated at run time.

Note You must manually place these data members outside the “//{{AFX_FIELD” comment brackets.

Typically, the parameter helps narrow the selection, as in the following example. Based on the sample class at the beginning of this article, the recordset object might execute the following SQL statement:

SELECT CourseID, CourseTitle FROM Course WHERE CourseID = ?

The “?” is a placeholder for a parameter value that you supply at run time. When you construct the recordset and set its m_strIDParam data member to “MATH101”, the effective SQL statement for the recordset becomes:

SELECT CourseID, CourseTitle FROM Course WHERE CourseID = MATH101

By defining parameter data members, you tell the framework about parameters in the SQL string. The framework binds the parameter, which lets ODBC know where to get values to substitute for the placeholder. In the example, the resulting recordset contains only the record from the Course table with a CourseID column whose value is “MATH101”. All specified columns of this record are selected. You can specify as many parameters (and placeholders) as you need.

Note MFC does nothing itself with the parameters — in particular, it doesn’t perform a text substitution. Instead, MFC tells ODBC where to get the parameter; ODBC retrieves the data and performs the necessary parameterization.

Important The order of parameters is important. For details about this and more information about parameters, see the article Recordset: Parameterizing a Recordset (ODBC).

Using m_nFields and m_nParams

When ClassWizard writes a constructor for your class, it also initializes the m_nFields data member, which specifies the number of field data members in the class. If you add any parameters to your class, you must also add an initialization for the m_nParams data member, which specifies the number of parameter data members. The framework uses these values to work with the data members.

For more information and examples, see the article Record Field Exchange: Using RFX.

See Also Recordset: Declaring a Class for a Table (ODBC), Record Field Exchange


Recordset: Declaring a Class for a Table (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

The most common recordset class opens a single table. To declare a recordset class for a single table, use ClassWizard. In ClassWizard, choose each column you want by naming a corresponding recordset field data member. See the article ClassWizard: Creating a Recordset Class.

Other uses for recordsets include:

  • Joining two or more tables.

  • Containing the results of a predefined query.

See Also Recordset: Creating and Closing Recordsets (ODBC), Recordset: Declaring a Class for a Predefined Query (ODBC), Recordset: Performing a Join (ODBC)


Recordset: Creating and Closing Recordsets (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

To use a recordset, construct a recordset object, then call its Open member function to run the recordset’s query and select records. When you finish with the recordset, close and destroy the object.

This article explains:

  • When and how to create a recordset object .

  • When and how you can qualify the recordset’s behavior by parameterizing, filtering, sorting, or locking it.

  • When and how to close a recordset object.

Creating Recordsets at Run Time

Before you can create recordset objects in your program, you typically write application-specific recordset classes. For more information on this preliminary step, see the article ClassWizard: Creating a Recordset Class.

Open a dynaset or snapshot object when you need to select records from a data source. The type of object to create depends on what you need to do with the data in your application and on what your ODBC driver supports. For more information, see the articles Dynaset and Snapshot.

To open a recordset

  1. Construct an object of your CRecordset-derived class.

    You can construct the object on the heap or on the stack frame of a function.

  2. Optionally modify the default recordset behavior. For the available options, see Setting Recordset Options.

  3. Call the object’s Open member function.

In the constructor, pass a pointer to a CDatabase object, or pass NULL to use a temporary database object that the framework will construct and open based on the connection string returned by the GetDefaultConnect member function. The CDatabase object may or may not already be connected to a data source.

The call to Open uses SQL to select records from the data source. The first record selected (if any) is the “current record”. The values of this record’s fields are stored in the recordset object’s field data members. If any records were selected, both the IsBOF and IsEOF member functions return 0.

In your Open call, you can:

  • Specify whether the recordset is a dynaset or snapshot. Recordsets open as snapshots by default. Or you can specify a forward-only recordset, which allows only forward scrolling, one record at a time.

    By default, a recordset uses the default type stored in the CRecordset data member m_nDefaultType. Wizards write code to initialize m_nDefaultType to the recordset type you choose in the wizard. Rather than accepting this default, you can substitute another recordset type.

  • Specify a string to replace the default SQL SELECT statement that the recordset constructs.

  • Specify whether the recordset is read-only or append-only. Recordsets allow full updating by default, but you can limit that to adding new records only or you can disallow all updates.

The following example shows how to open a read-only snapshot object of class CStudentSet, an application-specific class:

// Construct the snapshot object
CStudentSet rsStudent( NULL );
// Set options if desired, then open the recordset
if(!rsStudent.Open(CRecordset::snapshot, NULL, CRecordset::readOnly))
    return FALSE;
// Use the snapshot to operate on its records...

After you call Open, use the member functions and data members of the object to work with the records. In some cases, you may want to requery or refresh the recordset to include changes that have occurred on the data source. See the article Recordset: Requerying a Recordset (ODBC).

Tip The connect string you use during development might not be the same connect string that your eventual users need. For ideas about generalizing your application in this regard, see the article Data Source: Managing Connections (ODBC).

Setting Recordset Options

After you construct your recordset object but before you call Open to select records, you may want to set some options to control the recordset’s behavior. For all recordsets, you can:

  • Specify a filter to constrain record selection.

  • Specify a sort order for the records.

  • Specify parameters so you can select records using information obtained or calculated at run time.

You can also set the following option if conditions are right:

  • If the recordset is updatable and supports locking options, specify the locking method used for updates.

Important To affect record selection, you must set these options before you call the Open member function.

Closing a Recordset

When you finish with your recordset, you must dispose of it and deallocate its memory.

To close a recordset

  1. Call its Close member function.

  2. Destroy the recordset object.

    If you declared it on the stack frame of a function, the object is destroyed automatically when the object goes out of scope. Otherwise, use the delete operator.

Close frees the recordset’s HSTMT handle. It doesn’t destroy the C++ object.

See Also Recordset: Scrolling (ODBC), Recordset: Adding, Updating, and Deleting Records (ODBC)


Recordset: Scrolling (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

After you open a recordset, you need to access the records to display values, do calculations, generate reports, and so on. Scrolling lets you move from record to record within your recordset.

This article explains:

  • How to scroll from one record to another in a recordset

  • Under what circumstances scrolling is and is not supported

Scrolling from One Record to Another

Class CRecordset provides the Move member functions for scrolling within a recordset. These functions move the current record by rowsets. If you have implemented bulk row fetching, a Move operation repositions the recordset by the size of the rowset. If you have not implemented bulk row fetching, a call to a Move function repositions the recordset by one record each time. For more information about bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

Note When moving through a recordset, deleted records may not be skipped. See the IsDeleted member function for details.

In addition to the Move functions, CRecordset provides member functions for checking whether you have scrolled past the end or ahead of the beginning of your recordset.

To determine whether scrolling is possible in your recordset, call the CanScroll member function.

To scroll

  • Forward one record or one rowset: call the MoveNext member function.

  • Backward one record or one rowset: call the MovePrev member function.

  • To the first record in the recordset: call the MoveFirst member function.

  • To the last record in the recordset or to the last rowset: call the MoveLast member function.

  • N records relative to the current position: call the Move member function.

To test for the end or the beginning of the recordset

  • Have you scrolled past the last record? Call the IsEOF member function.

  • Have you scrolled ahead of the first record (moving backward)? Call the IsBOF member function.

The following code example uses IsBOF and IsEOF to detect the limits of a recordset when scrolling in either direction.

// Open a recordset; first record is current
CCustSet rsCustSet( NULL );
rsCustSet.Open( );

if( rsCustSet.IsBOF( ) )
    return;
    // The recordset is empty

// Scroll to the end of the recordset, past
// the last record, so no record is current
while ( !rsCustSet.IsEOF( ) )
    rsCustSet.MoveNext( );

// Move to the last record
rsCustSet.MoveLast( );

// Scroll to beginning of the recordset, before
// the first record, so no record is current
while( !rsCustSet.IsBOF( ) )
    rsCustSet.MovePrev( );

// First record is current again
rsCustSet.MoveFirst( );

IsEOF returns a nonzero value if the recordset is positioned past the last record. IsBOF returns a nonzero value if the recordset is positioned ahead of the first record (before all records). In either case, there is no current record to operate on. If you call MovePrev when IsBOF is already TRUE, or call MoveNext when IsEOF is already TRUE, the framework throws a CDBException. You can also use IsBOF and IsEOF to check for an empty recordset.

For more information about recordset navigation, see the article Recordset: Bookmarks and Absolute Positions (ODBC).

When Scrolling Is Supported

As originally designed, SQL provided only forward scrolling, but ODBC extends scrolling capabilities. The available level of support for scrolling depends on the ODBC driver(s) your application will work with, your driver’s ODBC API conformance level, and whether the ODBC Cursor Library is loaded into memory. For more information, see the articles ODBC and ODBC: The ODBC Cursor Library.

Tip You can control whether the cursor library is used. See the bUseCursorLib and dwOptions parameters to CDatabase::Open.

Note Unlike the MFC DAO classes, the MFC ODBC classes do not provide a set of Find functions for locating the next (or previous) record that meets specified criteria.

See Also CRecordset::CanScroll, CRecordset::CheckRowsetError, Recordset: Filtering Records (ODBC)


Recordset: Bookmarks and Absolute Positions (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

When navigating through a recordset, you often need a way of returning to a particular record. A record's bookmark and absolute position provide two such methods.

This article explains:

  • How to use bookmarks.

  • How to set the current record using absolute positions.

Bookmarks in MFC ODBC

A bookmark uniquely identifies a record. When you navigate through a recordset, you can't always rely on the absolute position of a record since records can be deleted from the recordset. The reliable way to keep track of the position of a record is to use its bookmark. Class CRecordset supplies member functions for:

  • Getting the bookmark of the current record, so you can save it in a variable (GetBookmark).

  • Moving quickly to a given record by specifying its bookmark, which you saved earlier in a variable (SetBookmark).

The following example illustrates how to use these member functions to mark the current record and later return to it:

// rs is a CRecordset or
// CRecordset-derived object

CDBVariant varRecordToReturnTo;
rs.GetBookmark( varRecordToReturnTo );

// More code in which you
// move to other records

rs.SetBookmark( varRecordToReturnTo );

You do not need to extract the underlying data type from the CDBVariant object. Simply assign the value with GetBookmark and return to that bookmark with SetBookmark.

Note Depending on your ODBC driver and recordset type, bookmarks may not be supported. You can easily determine whether bookmarks are supported by calling CRecordset::CanBookmark. Furthermore, if bookmarks are supported, you must explicitly choose to implement them by specifying the CRecordset::useBookmarks option in the Open member function. You should also check the persistence of bookmarks after certain recordset operations. For example, if you Requery a recordset, bookmarks may no longer be valid. Call CDatabase::GetBookmarkPersistence to check whether you can safely call SetBookmark.

Absolute Positions in MFC ODBC

Besides bookmarks, class CRecordset allows you to set the current record by specifying an ordinal position. This is called absolute positioning.

Note Absolute positioning is not available on forward-only recordsets. For more information about forward-only recordsets, see the article Recordset (ODBC).

To move the current record pointer using absolute position, call CRecordset::SetAbsolutePosition. When you pass a value to SetAbsolutePosition, the record corresponding to that ordinal position becomes the current record.

Important The absolute position of a record is potentially unreliable. If the user deletes records from the recordset, the ordinal position of any subsequent record will change. Bookmarks are the recommended method for moving the current record. See Bookmarks in MFC ODBC.

For more information about recordset navigation, see the article Recordset: Scrolling (ODBC).


Recordset: Filtering Records (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains how to filter a recordset so that it selects only a particular subset of the available records. For example, you might want to select only the class sections for a particular course, such as MATH101. A filter is a search condition defined by the contents of an SQL WHERE clause. When the framework appends it to the recordset’s SQL statement, the WHERE clause constrains the selection.

You must establish a recordset object’s filter after you construct the object but before you call its Open member function (or before you call the Requery member function for an existing recordset object whose Open member function has been called previously).

To specify a filter for a recordset object

  1. Construct a new recordset object (or prepare to call Requery for an existing object).

  2. Set the value of the object’s m_strFilter data member.

    The filter is a null-terminated string. It contains the contents of the SQL WHERE clause but not the keyword WHERE. For example, use

    m_pSet->m_strFilter = "CourseID = 'MATH101'";

    not

    m_pSet->m_strFilter = "WHERE CourseID = 'MATH101'";

    Note The literal string “MATH101” is shown with single quotation marks above. In the ODBC SQL specification, single quotes are used to denote a character string literal. Check your ODBC driver documentation for the quoting requirements of your DBMS in this situation. This syntax is also discussed further near the end of this article.

  3. Set any other options you need, such as sort order, locking mode, or parameters. Specifying a parameter is especially useful. For information on parameterizing your filter, see the article Recordset: Parameterizing a Recordset (ODBC).

  4. Call Open for the new object (or Requery for a previously opened object).

Tip Using parameters in your filter is potentially the most efficient method for retrieving records.

Tip Recordset filters are useful for joining tables and for using parameters based on information obtained or calculated at run time.

The recordset selects only those records that meet the search condition you specified. For example, to specify the course filter described above (assuming a variable strCourseID currently set, for instance, to “MATH101”), do the following:

// Using the recordset pointed to by m_pSet

// Set the filter
m_pSet->m_strFilter = "CourseID = " + strCourseID;

// Run the query with the filter in place
if ( m_pSet->Open( CRecordset::snapshot, NULL, CRecordset::readOnly ) )

// Use the recordset

The recordset contains records for all class sections for MATH101.

Notice how the filter string was set in the example above, using a string variable. This is the typical usage. But suppose you wanted to specify the literal value 100 for the course ID. The following code shows how to set the filter string correctly with a literal value:

m_strFilter = "StudentID = '100'";   // correct

Note the use of single quote characters; if you set the filter string directly, the filter string is not:

m_strFilter = "StudentID = 100";   // incorrect for some drivers

The quoting shown above conforms to the ODBC specification, but some DBMSs may require other quote characters. For more information, see the article SQL: Customizing Your Recordset’s SQL Statement (ODBC).

Note If you choose to override the recordset’s default SQL string by passing your own SQL string to Open, you should not set a filter if your custom string has a WHERE clause. For more information about overriding the default SQL, see the article SQL: Customizing Your Recordset’s SQL Statement (ODBC).

See Also Recordset: Sorting Records (ODBC), Recordset: How Recordsets Select Records (ODBC), Recordset: How Recordsets Update Records (ODBC), Recordset: Locking Records (ODBC)


Recordset: Sorting Records (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains how to sort your recordset. You can specify one or more columns on which to base the sort, and you can specify ascending or descending order (ASC or DESC; ASC is the default) for each specified column. For example, if you specify two columns, the records are sorted first on the first column named, then on the second column named. An SQL ORDER BY clause defines a sort. When the framework appends the ORDER BY clause to the recordset’s SQL query, the clause controls the selection’s ordering.

You must establish a recordset’s sort order after you construct the object but before you call its Open member function (or before you call the Requery member function for an existing recordset object whose Open member function has been called previously).

To specify a sort order for a recordset object

  1. Construct a new recordset object (or prepare to call Requery for an existing one).

  2. Set the value of the object’s m_strSort data member.

    The sort is a null-terminated string. It contains the contents of the ORDER BY clause but not the keyword ORDER BY. For example, use:

    recordset.m_strSort = "LastName DESC, FirstName DESC";

    not

    recordset.m_strSort = "ORDER BY LastName DESC, FirstName DESC";
  3. Set any other options you need, such as a filter, locking mode, or parameters.

  4. Call Open for the new object (or Requery for an existing object).

The selected records are ordered as specified. For example, to sort a set of student records in descending order by last name, then first name, do the following:

// Construct the recordset
CStudentSet rsStudent( NULL );
// Set the sort
rsStudent.m_strSort = "LastName DESC, FirstName DESC";
// Run the query with the sort in place
rsStudent.Open( );

The recordset contains all of the student records, sorted in descending order (Z to A) by last name, then by first name.

Note If you choose to override the recordset’s default SQL string by passing your own SQL string to Open, do not set a sort if your custom string has an ORDER BY clause.

See Also Recordset: Parameterizing a Recordset (ODBC), Recordset: Filtering Records (ODBC)


Recordset: Parameterizing a Recordset (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

Sometimes you’d like to be able to select records at run time, using information you’ve calculated or obtained from your end-user. Recordset parameters let you accomplish that goal.

This article explains:

  • The purpose of a parameterized recordset.

  • When and why you might want to parameterize a recordset.

  • How to declare parameter data members in your recordset class.

  • How to pass parameter information to a recordset object at run time.

Parameterized Recordsets

A parameterized recordset lets you pass parameter information at run time. This has two valuable effects:

  • It may result in better execution speed.

  • It lets you build a query at run time, based on information not available to you at design time, such as information obtained from your user or calculated at run time.

When you call Open to run the query, the recordset uses the parameter information to complete its SQL SELECT statement. You can parameterize any recordset.

When to Use Parameters

Typical uses for parameters include:

  • Passing run-time arguments to a predefined query.

    To pass parameters to a stored procedure, you must specify a complete custom ODBC CALL statement — with parameter placeholders — when you call Open, overriding the recordset’s default SQL statement. See CRecordset::Open in the Class Library Reference and the articles SQL: Customizing Your Recordset’s SQL Statement (ODBC) and Recordset: Declaring a Class for a Predefined Query (ODBC).

  • Efficiently performing numerous requeries with different parameter information.

    For example, each time your end-user looks up information for a particular student in the student registration database, you can specify the student’s name or ID as a parameter obtained from the user. Then, when you call your recordset’s Requery member function, the query selects only that student’s record.

    Your recordset’s filter string, stored in m_strFilter, might look like this:

    "StudentID = ?"

    Suppose you obtain the student ID in the variable strInputID. When you set a parameter to strInputID (for example, the student ID 100) the value of the variable is bound to the parameter placeholder represented by the “?” in the filter string.

    Assign the parameter value as follows:

    strInputID = "100";
...
m_strParam = strInputID;

    Note that you would not want to set up a filter string this way:

    m_strFilter = "StudentID = 100";   // 100 is incorrectly quoted
                                   // for some drivers

    For a discussion of how to use quotes correctly for filter strings, see the article Recordset: Filtering Records (ODBC).

    The parameter value is different each time you requery the recordset for a new student ID.

    Tip Using a parameter is more efficient than simply a filter. For a parameterized recordset, the database must process an SQL SELECT statement only once. For a filtered recordset without parameters, the SELECT statement must be processed each time you Requery with a new filter value.

For more information about filters, see the article Recordset: Filtering Records (ODBC).

Parameterizing Your Recordset Class

Note This section applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, implementing parameters is a similar process. For more information, see the article Recordset: Fetching Records in Bulk (ODBC).

Before you create your recordset class, determine what parameters you need, what their data types are, and how the recordset will use them.

To parameterize a recordset class

  1. Run ClassWizard and create the class. See the article ClassWizard: Creating a Recordset Class.

  2. Specify field data members for the recordset’s columns.

  3. After ClassWizard writes the class to a file in your project, go to the .H file and manually add one or more parameter data members to the class declaration. The addition might look something like the following example, part of a snapshot class designed to answer the query “Which students are in the senior class?”
    class CStudentSet : public CRecordset
{
// Field/Param Data
    //{{AFX_FIELD(CStudentSet, CRecordset)
    CString m_strFirstName;
    CString m_strLastName;
    CString m_strStudentID;
    CString m_strGradYear;
    //}}AFX_FIELD

    CString m_strGradYrParam;
};

    ClassWizard writes field data members inside the “//{{AFX_FIELD” comment brackets. You add your parameter data members outside the comment brackets. The convention is to append the word “Param” to each name.

  4. Modify the DoFieldExchange member function definition in the .CPP file. Add an RFX function call for each parameter data member you added to the class. For information on writing your RFX functions, see the article Record Field Exchange: How RFX Works. Precede the RFX calls for the parameters with a single call to
    pFX->SetFieldType( CFieldExchange::param );
// RFX calls for parameter data members
  5. In the constructor of your recordset class, increment the count of parameters, m_nParams.

    For information, see The Recordset Constructor in the article Record Field Exchange: Working with the Wizard Code.

  6. When you write the code that creates a recordset object of this class, place a “?” (question mark) symbol in each place in your SQL statement string(s) where a parameter is to be replaced.

    At run time, “?” placeholders are filled, in order, by the parameter values you pass. The first parameter data member set after the SetFieldType call replaces the first “?” in the SQL string, the second parameter data member replaces the second “?”, and so on.

Important Parameter order is important: the order of RFX calls for parameters in your DoFieldExchange function must match the order of the parameter placeholders in your SQL string.

Tip The most likely string to work with is the string you specify (if any) for the class’s m_strFilter data member, but some ODBC drivers may allow parameters in other SQL clauses.

Passing Parameter Values at Run Time

You must specify parameter values before you call Open (for a new recordset object) or Requery (for an existing one).

To pass parameter values to a recordset object at run time

  1. Construct the recordset object.

  2. Prepare a string or strings, such as the m_strFilter string, containing the SQL statement, or part(s) of it. Put “?” placeholders where the parameter information is to go.

  3. Assign a run-time parameter value to each parameter data member of the object.

  4. Call the Open member function (or Requery, for an existing recordset).

For example, suppose you want to specify a filter string for your recordset using information obtained at run time. Assume you have constructed a recordset of class CStudentSet earlier — called rsStudents — and now want to requery it for a particular kind of student information.

// Set up a filter string with
// parameter placeholders
rsStudents.m_strFilter = "GradYear <= ?";

// Obtain or calculate parameter values
// to pass--simply assigned here
CString strGradYear = GetCurrentAcademicYear( );

// Assign the values to parameter data members
rsStudents.m_strGradYrParam = strGradYear;

// Run the query
if( !rsStudents.Requery( ) )
    return FALSE;

The recordset contains records for those students whose records meet the conditions specified by the filter, which was constructed from run-time parameters. In this case, the recordset contains records for all senior students.

Note If needed, you can set the value of a parameter data member to Null, using SetParamNull. You can likewise check whether a parameter data member is Null, using IsFieldNull.

See Also Recordset: Adding, Updating, and Deleting Records (ODBC), Recordset: How Recordsets Select Records (ODBC)


Recordset: Adding, Updating, and Deleting Records (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

Note You can now add records in bulk more efficiently. For information, see the article Recordset: Adding Records in Bulk (ODBC).

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

Updatable snapshots and dynasets allow you to add, edit (update), and delete records. This article explains:

  • How to determine whether your recordset is updatable.

  • How to add a new record.

  • How to edit an existing record.

  • How to delete a record.

For more information about how updates are carried out and how your updates appear to other users, see the article Recordset: How Recordsets Update Records (ODBC). Normally, when you add, edit, or delete a record, the recordset changes the data source immediately. You can instead batch groups of related updates into transactions. If a transaction is in progress, the update doesn’t become final until you commit the transaction. This allows you to take back or roll back the changes. For information about transactions, see the article Transaction (ODBC).

The following table summarizes the options available for recordsets with different update characteristics.

Recordset Read/Update Options

Type | Read | Edit records | Delete records | Add new (append)
Read-only | Y | N | N | N
Append-only | Y | N | N | Y
Fully updatable | Y | Y | Y | Y

Determining Whether Your Recordset is Updatable

A recordset object is updatable if the data source is updatable, and you opened the recordset as updatable. Its updatability also depends on the SQL statement you use, the capabilities of your ODBC driver, and whether the ODBC Cursor Library is in memory or not. You can’t update a read-only recordset or data source.

To determine whether your recordset is updatable

  • Call the recordset object’s CanUpdate member function.

    CanUpdate returns a nonzero value if the recordset is updatable.

By default, recordsets are fully updatable (you can perform AddNew, Edit, and Delete operations). But you can also use the appendOnly option to open updatable recordsets. A recordset opened this way allows only the addition of new records with AddNew. You can’t edit or delete existing records. You can test whether a recordset is open only for appending by calling the CanAppend member function. CanAppend returns a nonzero value if the recordset is either fully updatable or open only for appending.

The following code shows how you might use CanUpdate for a recordset object called rsStudentSet:

if( !rsStudentSet.Open( ) )
    return FALSE;
if( !rsStudentSet.CanUpdate( ) )
{
    AfxMessageBox( "Unable to update the Student recordset." );
    return;
}

Caution When you prepare to update a recordset by calling Update, take care that your recordset includes all columns making up the primary key of the table (or all of the columns of any unique index on the table). In some cases, the framework can use only the columns selected in your recordset to identify which record in your table to update. Without all the necessary columns, multiple records may be updated in the table, possibly damaging the referential integrity of the table. In this case, the framework will throw exceptions when you call Update.

Adding a Record to a Recordset

You can add new records to a recordset if its CanAppend member function returns a nonzero value.

To add a new record to a recordset

  1. Make sure the recordset is appendable.

  2. Call the recordset object’s AddNew member function.

    AddNew prepares the recordset to act as an edit buffer. All field data members are set to the special value Null and marked as unchanged so only changed (“dirty”) values will be written to the data source when you call Update.

  3. Set the values of the new record’s field data members.

    Assign values to the field data members. Those you don’t assign will not be written to the data source.

  4. Call the recordset object’s Update member function.

    Update completes the addition by writing the new record to the data source. For what happens if you fail to call Update, see the article Recordset: How Recordsets Update Records (ODBC).

For information about how adding records works and about when added records are visible in your recordset, see the article Recordset: How AddNew, Edit, and Delete Work (ODBC).

The following example shows how to add a new record:

if( !rsStudent.Open( ) )
    return FALSE;
if( !rsStudent.CanAppend( ) )
    return FALSE;                      // no field values were set
rsStudent.AddNew( );
rsStudent.m_strName = strName;
rsStudent.m_strCity = strCity;
rsStudent.m_strStreet = strStreet;
if( !rsStudent.Update( ) )
{
    AfxMessageBox( "Record not added; no field values were set." );
    return FALSE;
}

For additional information, see Adding a Record in the article Recordset: How AddNew, Edit, and Delete Work.

Tip To cancel an AddNew or Edit call, simply make another call to AddNew or Edit or call Move with the AFX_MOVE_REFRESH parameter. Data members will be reset to their previous values and you will still be in Edit or Add mode.

Editing a Record in a Recordset

You can edit existing records if your recordset’s CanUpdate member function returns a nonzero value.

To edit an existing record in a recordset

  1. Make sure the recordset is updatable.

  2. Scroll to the record you want to update.

  3. Call the recordset object’s Edit member function.

    Edit prepares the recordset to act as an edit buffer. All field data members are marked so that the recordset can tell later whether they were changed. The new values for changed field data members are written to the data source when you call Update.

  4. Set the values of the new record’s field data members.

    Assign values to the field data members. Those you don’t assign values will remain unchanged.

  5. Call the recordset object’s Update member function.

    Update completes the edit by writing the changed record to the data source. For what happens if you fail to call Update, see the article Recordset: How Recordsets Update Records (ODBC).

After you edit a record, the edited record remains the current record.

The following example shows an Edit operation. It assumes the user has moved to a record he or she wants to edit.

rsStudent.Edit( );
rsStudent.m_strStreet = strNewStreet;
rsStudent.m_strCity = strNewCity;
rsStudent.m_strState = strNewState;
rsStudent.m_strPostalCode = strNewPostalCode;
if( !rsStudent.Update( ) )
{
    AfxMessageBox( "Record not updated; no field values were set." );
    return FALSE;
}

For more information, see Editing an Existing Record in the article Recordset: How AddNew, Edit, and Delete Work.

Tip To cancel an AddNew or Edit call, simply make another call to AddNew or Edit or call Move with the AFX_MOVE_REFRESH parameter. Data members will be reset to their previous values and you will still be in Edit or Add mode.

Deleting a Record from a Recordset

You can delete records if your recordset’s CanUpdate member function returns a nonzero value.

To delete a record

  1. Make sure the recordset is updatable.

  2. Scroll to the record you want to update.

  3. Call the recordset object’s Delete member function.

    Delete immediately marks the record as deleted, both in the recordset and on the data source.

    Unlike AddNew and Edit, Delete has no corresponding Update call.

  4. Scroll to another record.

    Important When moving through the recordset, deleted records may not be skipped. See the IsDeleted member function for details.

The following example shows a Delete operation. It assumes the user has moved to a record he or she wants to delete. After Delete is called, it’s important to move to a new record.

rsStudent.Delete( );
rsStudent.MoveNext( );

For more information about the effects of the AddNew, Edit, and Delete member functions, see the article Recordset: How Recordsets Update Records (ODBC).

See Also Recordset: Locking Records (ODBC)


Recordset: Adding Records in Bulk (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

The MFC CRecordset class has a new optimization (in both 16- and 32-bit versions) that improves efficiency when you’re adding new records in bulk to a table.

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

A new option for the dwOptions parameter to the CRecordset::Open member function, optimizeBulkAdd, improves performance when you’re adding multiple records consecutively without calling Requery or Close. Only those fields that are “dirty” prior to the first Update call are marked as “dirty” for subsequent AddNew/Update calls.

If you are using the database classes to take advantage of the ::SQLSetPos ODBC API function for adding, editing, and deleting records, this optimization is unnecessary.

If the ODBC Cursor Library is loaded or the ODBC driver doesn’t support adding, editing, and deleting via ::SQLSetPos, this optimization should improve bulk add performance. To turn on this optimization, set the dwOptions parameter in the Open call for your recordset to :

appendOnly | optimizeBulkAdd

See Also Recordset: Adding, Updating, and Deleting Records (ODBC), Recordset: Locking Records (ODBC)


Recordset: Locking Records (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains:

  • The kinds of record locking available.

  • How to lock records in your recordset during updates.

When you use a recordset to update a record on the data source, your application can lock the record so no other user can update the record at the same time. The state of a record updated by two users at “the same time” is undefined unless the system can guarantee that two users can’t update a record simultaneously.

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If you have implemented bulk row fetching, some of the information does not apply. For example, you cannot call the Edit and Update member functions. For more information about bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

Record-Locking Modes

The database classes provide two record-locking modes:

  • Optimistic locking (the default)

  • Pessimistic locking

Updating a record occurs in three steps:

  1. You begin the operation by calling the Edit member function.

  2. You change the appropriate fields of the current record.

  3. You end the operation — and normally commit the update — by calling the Update member function.

Optimistic locking locks the record on the data source only during the Update call. If you use optimistic locking in a multiuser environment, the application should handle an Update failure condition. Pessimistic locking locks the record as soon as you call Edit and doesn’t release it until you call Update (failures are indicated via the CDBException mechanism, not by a value of FALSE returned by Update). Pessimistic locking has a potential performance penalty for other users, since concurrent access to the same record may have to wait until completion of your application’s Update process.

Locking Records in Your Recordset

If you want to change a recordset object’s locking mode from the default, you must change the mode before you call Edit.

To change the current locking mode for your recordset

  • Call the SetLockingMode member function, specifying either CRecordset::pessimistic or CRecordset::optimistic.

The new locking mode remains in effect until you change it again or the recordset is closed.

Note Relatively few ODBC drivers currently support pessimistic locking.

See Also Recordset: Performing a Join (ODBC), Recordset: Adding, Updating, and Deleting Records (ODBC)


Recordset: Performing a Join (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains:

  • What a join is.

  • How to perform a join of multiple tables.

What a Join Is

The join operation — a common data-access task — lets you work with data from more than one table using a single recordset object. Joining two or more tables yields a recordset that can contain columns from each table, but appears as a single table to your application. Sometimes the join uses all columns from all tables, but sometimes the SQL SELECT clause in a join uses only some of the columns from each table. The database classes support read-only joins but not updatable joins.

The key to a join operation is one or more columns that the tables have in common. For example, suppose there is a “CourseID” column in both the Course table and the Section table for an application such as the ENROLL tutorial. In the Course table, the CourseID column contains a unique ID value for each possible course. In the Section table, the CourseID column probably doesn’t contain unique values, since each course usually has more than one section.

To select records containing columns from joined tables, you need the following items:

  • A table list containing the names of all tables being joined.

  • A column list containing the names of all participating columns. Columns with the same name but from different tables are qualified by the table name.

  • A filter (SQL WHERE clause) that specifies the column(s) on which the tables are joined. This filter takes the form “Table1.KeyCol = Table2.KeyCol” and actually accomplishes the join. For the ENROLL example above, the filter is:
    Course.CourseID = Section.CourseID

Performing the Join

The following procedure shows a join of two tables but can apply to joins of any number of tables (all on the same data source). The procedure involves first binding columns from multiple tables with ClassWizard, then directly modifying source code to complete the join.

Binding the Table Columns

To bind columns from both tables to a single recordset

  1. Use ClassWizard to create a recordset class for the join. In ClassWizard choose Data Sources to open the Data Sources dialog box and bind columns from the first table to recordset field data members.

    See the article ClassWizard: Creating a Recordset Class.

  2. Choose ClassWizard’s Update Columns button to open the Data Sources dialog box a second time.

  3. Select a data source and choose OK to close the Data Sources dialog box.

  4. In the Tables dialog box, select the name of the second table and choose OK to close the dialog box.

  5. Bind columns from the second table to additional recordset field data members.

    If any column names from the second table duplicate column names from the first table, be sure to give the corresponding recordset field data members unique names. For example, if you’re joining Instructor and Section tables, each table might contain a column named RoomNo; you might bind one column to m_strInstrOffice and the other to m_strClassRoom.

  6. Close ClassWizard.

Note When creating CRecordset-derived or CDaoRecordset-derived classes with ClassWizard, be careful when selecting multiple tables or queries. Selecting multiple tables or queries will result in the construction of a join query without any restriction on how to perform the join (called a cross-product or cartesian product join). You may want to specify a filter using CRecordset::m_strFilter or CDaoRecordset::m_strFilter (resulting in MFC building an SQL WHERE clause) before the recordset is opened. This will constrain the number of records in the result set. This is especially necessary when using the ODBC Cursor Library, since the Cursor Library may create a large temporary file for result sets with many records.

Modifying the Source Files

Once you create the recordset class with ClassWizard, you must customize two parts of the class code. First, edit the class’s table list, then qualify any columns with the same name but from different tables. You’ll need to edit the calls in your DoFieldExchange override to insert table names.

For example, the student registration database for the MFC Tutorial sample ENROLL contains Instructor and Section tables. The Instructor table contains the following columns:

  • InstructorID

  • Name

  • RoomNo (the instructor’s office)

The Section table contains the following columns:

  • InstructorID

  • Schedule

  • RoomNo (where the class is held)

  • SectionNo

  • CourseID

  • Capacity (maximum size of the section)

To modify the recordset’s table list

  • Rewrite the recordset’s GetDefaultSQL member function to return a string containing a comma-delimited list of table names.

For example, if your CJoinSet recordset joins a Course table to a Section table, you should rewrite your GetDefaultSQL function to look something like this:

CString CJoinSet::GetDefaultSQL()
{
    return "SECTION, INSTRUCTOR";
}

Tip As an alternative, you can pass a string containing a comma-delimited list of table names in the lpszSQL parameter when you call the recordset’s Open member function. The string has the same form as the string returned in the example above.

To qualify columns with the same name from different tables

  • Edit the RFX or Bulk RFX function calls in the recordset’s DoFieldExchange or DoBulkFieldExchange member function.

    For each duplicate column name, edit the second parameter in the RFX or Bulk RFX call to prefix a table name to the column name already there. Separate the table name and the column name with a period.

For example, because CJoinSet binds a RoomNo column from each table, you must modify the two RFX calls for these columns as shown in the following code:

void CJoinSet::DoFieldExchange(CFieldExchange* pFX)
{
    //{{AFX_FIELD_MAP(CJoinSet)
    SetFieldType(pFX, CFieldExchange::outputColumn);
    RFX_Text(pFX, "Section.RoomNo", m_strClassRoom);
    RFX_Text(pFX, "Instructor.RoomNo", m_strInstructorOffice);
    // ...
    //}}AFX_FIELD_MAP
}

In the second parameter of each RFX function call above, the name RoomNo is prefixed by the table name. The two items are separated by a period.

Setting the Join Conditions with a Filter

When you construct a CJoinSet object in your program, set its filter to specify which columns constitute the join. Then call the recordset’s Open member function as shown in the following example, which joins the Instructor and Section tables on their common InstructorID column:

CJoinSet ssJoin( NULL );
ssJoin.m_strFilter = "Instructor.InstructorID = Section.InstructorID";
if( !ssJoin.Open( ) )
    return FALSE;        // recordset could not be opened

The filter supplies the connection between two columns that makes it possible to view two tables as if they were one.

You can join more than two tables in the same way by equating multiple pairs of columns, each pair joined by the SQL keyword AND.

See Also Recordset: Declaring a Class for a Predefined Query (ODBC), Recordset: Declaring a Class for a Table (ODBC), Recordset: Requerying a Recordset (ODBC)


Recordset: Declaring a Class for a Predefined Query (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains how to create a recordset class for a predefined query (sometimes called a “stored procedure,” as in Microsoft SQL Server).

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If bulk row fetching is implemented, the process is very similar. To understand the differences between recordsets that implement bulk row fetching and those that do not, see the article Recordset: Fetching Records in Bulk (ODBC).

Some database management systems (DBMSs) allow you to create a predefined query and call it from your programs like a function. The query has a name, may or may not take parameters, and may or may not return records. The procedure in this article describes how to call a predefined query that returns records (and perhaps takes parameters).

The database classes don’t support updating predefined queries. The difference between a snapshot predefined query and a dynaset predefined query is not updatability but whether changes made by other users (or other recordsets in your program) are visible in your recordset.

Tip You don’t need a recordset to call a predefined query that doesn’t return records. Prepare the SQL statement as described below, but execute it by calling the CDatabase member function ExecuteSQL.

You can create a single recordset class to manage calling a predefined query, but you must do some of the work yourself. ClassWizard doesn’t support creating a class specifically for this purpose.

To create a class for calling a predefined query (stored procedure)

  1. Use ClassWizard to create a recordset class for the table that contributes the most columns returned by the query. This gives you a head start.

  2. Manually add field data members for any columns of any tables that the query returns but that ClassWizard didn’t create for you. Add them outside the “//{{AFX_FIELD” comments.

    For example, if the query returns three columns each from two additional tables, add six field data members (of the appropriate data types) to the class.

  3. Manually add RFX function calls in the DoFieldExchange member function of the class, one corresponding to the data type of each added field data member.
    Add these function calls outside the “//{{AFX_FIELD_MAP” comments. Immediately before these RFX calls, call SetFieldType, as shown here:
pFX->SetFieldType( CFieldExchange::outputColumn );

    Note You must know the data types and the order of columns returned in the result set. The order of RFX function calls in DoFieldExchange must match the order of result set columns.

  4. Manually add initializations for the new field data members in the recordset class constructor.

    You must also increment the initialization value for the m_nFields data member. ClassWizard writes the initialization, but it only covers the field data members it adds for you. Put the increment statement outside the comment brackets. For example:

    m_nFields += 6;
//{{AFX_FIELD(CDelinquents, CRecordset)
...
//}}AFX_FIELD

    Some data types shouldn’t be initialized here, for example, CLongBinary or byte arrays.

  5. If the query takes parameters, add a parameter data member for each parameter, an RFX function call for each, and an initialization for each.

  6. You must increment m_nParams for each added parameter, as you did m_nFields for added fields in step 4 above. See the article Recordset: Parameterizing a Recordset (ODBC) for details.

  7. Manually write an SQL statement string with the following form:
    {CALL proc-name [(? [, ?]...)]}

    where CALL is an ODBC keyword, proc-name is the name of the query as it is known on the data source, and the “?” items are placeholders for the parameter values you supply to the recordset at run time (if any). The following example prepares a placeholder for one parameter:

    CString mySQL = "{CALL Delinquent_Accts (?)}";
  8. In the code that opens the recordset, first set the values of the recordset’s parameter data members, then call the Open member function, passing your SQL string for the lpszSQL parameter. Or instead, replace the string returned by the GetDefaultSQL member function in your class.

The following examples illustrate the procedure for calling a predefined query, named Delinquent_Accts, which takes one parameter for a sales district number. This query returns three columns: Acct_No, L_Name, Phone. All columns are from the Customers table.

The recordset below specifies field data members for the columns the query returns and a parameter for the sales district number requested at run time.

class CDelinquents : public CRecordset
{
// Field/Param Data
    //{{AFX_FIELD(CDelinquents, CRecordset)
    LONG m_lAcct_No;
    CString m_strL_Name;
    CString m_strPhone;
    //}}AFX_FIELD
    LONG m_lDistParam;
    // ...
};

This class declaration is as ClassWizard writes it, except for the m_lDistParam member added manually outside the “//{{AFX_FIELD” comment. Other members below the comments aren’t shown here.

The next example shows the initializations for the data members in the CDelinquents constructor. You add the two lines outside the comment brackets.

CDelinquents::CDelinquents(CDatabase* pdb)
   : CRecordset(pdb)
{
    //{{AFX_FIELD_INIT(CDelinquents)
    m_lAcct_No = 0;
    m_strL_Name = "";
    m_strPhone = "";
    m_nFields = 3;
    //}}AFX_FIELD_INIT
    m_nParams = 1;
    m_lDistParam = 0;
}

Note the initializations for m_nFields and m_nParams. ClassWizard initializes m_nFields; you initialize m_nParams.

The next example shows the RFX functions in CDelinquents::DoFieldExchange:

void CDelinquents::DoFieldExchange(CFieldExchange* pFX)
{
//{{AFX_FIELD_MAP(CDelinquents)
    pFX->SetFieldType(CFieldExchange::outputColumn);
    RFX_Long(pFX, "Acct_No", m_lAcct_No);
    RFX_Text(pFX, "L_Name", m_strL_Name);
    RFX_Text(pFX, "Phone", m_strPhone);
//}}AFX_FIELD_MAP
    pFX->SetFieldType(CFieldExchange::param);
    RFX_Long(pFX, "Dist_No", m_lDistParam);
}

Besides making the RFX calls for the three returned columns, this code manages binding the parameter you pass at run time. The parameter is keyed to the Dist_No (district number) column.

The next example shows how to set up the SQL string and how to use it to open the recordset.

// Construct a CDelinquents recordset object
CDelinquents rsDel( NULL );
CString strSQL = "{CALL Delinquent_Accts (?)}"
// Specify a parameter value (obtained earlier from the user)
rsDel.m_lDistParam = lDistrict;
// Open the recordset and run the query
if( rsDel.Open( CRecordset::snapshot, strSQL ) )
    // Use the recordset ...

This code constructs a snapshot, passes it a parameter obtained earlier from the user, and calls the predefined query. When the query runs, it returns records for the specified sales district. Each record contains columns for the account number, customer’s last name, and customer’s phone number.

Tip You might want to handle a return value (output parameter) from a stored procedure. For more information and an example, see CFieldExchange::SetFieldType.

See Also Recordset: Requerying a Recordset (ODBC), Recordset: Declaring a Class for a Table (ODBC), Recordset: Performing a Join (ODBC)


Recordset: Requerying a Recordset (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains how you can use a recordset object to “requery” — refresh — itself from the database, and when you might want to do that with the Requery member function.

The principal reasons for requerying a recordset are to:

  • Bring the recordset up to date with respect to records added by you or by other users and records deleted by other users (those you delete are already reflected in the recordset).

  • Refresh the recordset based on changing parameter values.

Bringing the Recordset Up to Date

Frequently you will want to requery your recordset object to bring it up to date. In a multiuser database environment, other users can make changes to the data during the life of your recordset. For more information about when your recordset reflects changes made by other users and when other users’ recordsets reflect your changes, see the articles Recordset: How Recordsets Update Records (ODBC) and Dynaset.

Requerying Based on New Parameters

Another frequent — and equally important — use of Requery is to select a new set of records based on changing parameter values. For example, Step 2 in the ENROLL tutorial application illustrates using a combo box in a record view to select from a list of all available college courses. When the user selects a different course from the combo box, ENROLL requeries a Section table to select only those class sections for the course the user chose in the combo box. See the CSectionForm::OnSelendokCourseList member function in Requerying the CSectionSet Recordset in Tutorials.

Tip Query speed is probably significantly faster if you call Requery with changing parameter values than if you call Open again.

Requerying Dynasets vs. Snapshots

Because dynasets are meant to present a set of records with dynamic, up-to-date data, you’ll want to requery dynasets often if you want to reflect other users’ additions. Snapshots, on the other hand, are useful because you can safely rely on their static contents while you prepare reports, calculate totals, and so on. Still, you may sometimes want to requery a snapshot as well. In a multiuser environment, snapshot data may lose synchronization with the data source as other users change the database.

To requery a recordset object

  • Call the Requery member function of the object.

Alternatively, you can simply close and reopen the original recordset. In either case, the new recordset represents the current state of the data source.

For an example, see the article Record Views: Filling a List Box from a Second Recordset.

Tip To optimize Requery performance, avoid changing the recordset’s filter or sort. Change only the parameter value before calling Requery.

If the Requery call fails, you can retry the call, otherwise, your application should terminate gracefully. A call to Requery or Open might fail for any of a number of reasons. Perhaps a network error occurs; or, during the call, after the existing data is released but before the new data is obtained, another user might get exclusive access; or the table on which your recordset depends could be deleted.

See Also Recordset: Dynamically Binding Data Columns (ODBC), Recordset: Creating and Closing Recordsets (ODBC)


Recordset: Dynamically Binding Data Columns (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

Recordsets manage binding table columns that you specify at design time, but there are cases when you may want to bind columns that were unknown to you at design time. This article explains:

  • When you might want to bind columns dynamically to a recordset.

  • How to bind columns dynamically at run time.

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. The techniques described generally are not recommended if you are using bulk row fetching. For more information about bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

When You Might Bind Columns Dynamically

At design time, ClassWizard creates recordset classes based on the known tables and columns on your data source. Databases can change between when you design them and later when your application uses those tables and columns at run time. You or another user might add or drop a table or add or drop columns from a table that your application’s recordset relies upon. This probably isn’t a concern for all data-access applications, but if it is for yours, how can you cope with changes in the database schema, other than by redesigning and recompiling? The purpose of this article is to answer that question.

This article describes the most common case in which you might bind columns dynamically — having begun with a recordset based on a known database schema, you want to handle additional columns at run time. The article further assumes that the additional columns map to CString field data members, the most common case, although suggestions are supplied to help you manage other data types.

With a small amount of extra code, you can:

  • Determine what columns are available at run time.

  • Bind additional columns to your recordset dynamically, at run time.

Your recordset still contains data members for the columns you knew about at design time. It also contains a small amount of extra code that dynamically determines whether any new columns have been added to your target table and, if so, binds these new columns to dynamically allocated storage (rather than to recordset data members).

This article doesn’t cover other dynamic binding cases, such as dropped tables or columns. For those, you’ll need to use ODBC API calls more directly. See the ODBC SDK Programmer’s Reference on the MSDN Library CD.

Example code for this article comes from the MFC Database samples DYNABIND and CATALOG.

How to Bind Columns Dynamically

To bind columns dynamically in a case like that of the DYNABIND example, you must know (or be able to determine) the names of the additional columns. You must also allocate storage for the additional field data members, specify their names and their types, and specify the number of columns you’re adding.

The following discussion mentions two different recordsets. The first is the main recordset that selects records from the target table. The second is a special column recordset used to get information about the columns in your target table.

The General Process

At the most general level, you follow these steps:

  1. Construct your main recordset object.

    Optionally, pass a pointer to an open CDatabase object, or be able to supply connection information to the column recordset in some other way.

  2. Take steps to add columns dynamically.

    See the process described in Adding the Columns below.

  3. Open your main recordset.

    The recordset selects records and uses record field exchange (RFX) to bind both the static columns (those mapped to recordset field data members) and the dynamic columns (mapped to extra storage that you allocate).

Adding the Columns

Dynamically binding added columns at run time requires the following steps:

  1. Determine at run time what columns are in the target table. Extract from that information a list of the columns that have been added to the table since your recordset class was designed.

    A good approach is to use a column recordset class designed to query the data source for column information for the target table — such as column name, data type, and so on. The MFC Database sample CATALOG provides a recordset class called CColumns that you can use to build a list of the new columns’ names.

  2. Provide storage for the new field data members. Your main recordset class doesn’t have field data members for unknown columns, so you must provide a place to store the names, result values, and possibly data type information (if the columns are of different data types).

    One approach is to build one or more dynamic lists, one for the new columns’ names, another for their result values, and a third for their data types (if necessary). These lists, particularly the value list, provide the information and the necessary storage for binding. The following figure illustrates building the lists.

    Building Lists of Columns to Bind Dynamically

  3. Add an RFX function call in your main recordset’s DoFieldExchange function for each added column. These RFX calls do the work of fetching a record, including the additional columns, and binding the columns to recordset data members or to your dynamically supplied storage for them.

    One approach is to add a loop to your main recordset’s DoFieldExchange function that loops through your list of new columns, calling the appropriate RFX function for each column in the list. On each RFX call, pass a column name from the column name list and a storage location in the corresponding member of the result value list.

Lists of Columns

The four lists you need to work with are:

Current-Table-Columns (List 1 in the illustration)

A list of the columns currently in the table on the data source. This list may or may not match the list of columns currently bound in your recordset.

Bound-Recordset-Columns (List 2 in the illustration)

A list of the columns bound in your recordset (usually set up with ClassWizard). These columns already have RFX statements in your DoFieldExchange function.

Columns-To-Bind-Dynamically (List 3 in the illustration)

A list of columns in the table but not in your recordset. These are the columns you want to bind dynamically.

Dynamic-Column-Values (List 4 in the illustration) A list containing storage for the values retrieved from the columns you bind dynamically. Elements of this list correspond to those in Columns-to-Bind-Dynamically, one to one.

Building Your Lists

With a general strategy in mind, you can turn to the details. The procedures in the rest of this article show you how to build the lists shown in Lists of Columns. The procedures guide you through:

  • Determining the columns in your table at run time

  • Determining the names of columns not in your recordset

  • Providing dynamic storage for columns newly added to the table

  • Dynamically adding RFX calls for new columns

Determining the Columns in Your Table at Run Time

First, build Current-Table-Columns (as in the illustration): a list of the columns in the table on the data source.

To determine the columns in a table at run time (Current-Table-Columns)

  1. Borrow the files COLUMNST.H/.CPP from the MFC Database sample CATALOG. Add the .CPP file to your project and include the .H file as needed.

  2. At run time, construct a “column recordset” object of class CColumn, passing a pointer to an open CDatabase object.

  3. Before you call Open, set one or more of the column recordset’s parameters. The following table describes what these parameters specify.
    Parameter Description
    m_strQualifierParam
             Identifies the database containing the table for ODBC. You usually don’t need to specify this value.
    m_strOwnerParam
             Identifies the person who created the target table.
    m_strTableNameParam
             Identifies the target table by name.
    m_strColumnNameParam
             Identifies a specific column by name.

    In most cases, you need only the table name, although some data sources might require the owner name as well, and others might require even more information. In addition to table name, use the column name parameter if you need information for only a single column in the table. For information about these parameters, see ::SQLColumns in the ODBC SDK Programmer’s Reference on the MSDN Library CD.

  4. Call Open for the column recordset.

    The recordset returns a record for each column in the specified table (unless you specify m_strColumnNameParam).

  5. Construct Current-Table-Columns, a collection object that can hold CString objects.

    For example, you might use a CStringList.

  6. Scroll through the object’s records, loading column names into Current-Table-Columns as you go.

This procedure results in a collection object that contains the names of all columns in a specified table. For example, the illustration shows Current-Table-Columns (List 1) with four elements. The last element is “Phone.” For descriptions of the lists, see Lists of Columns.

Determining Which Table Columns Are Not in Your Recordset

Next, build a list (Bound-Recordset-Columns, as in List 2 in the illustration) that contains a list of the columns already bound in your main recordset. Then build a list (Columns-to-Bind-Dynamically, derived from Current-Table-Columns and Bound-Recordset-Columns) that contains column names that are in the table on the data source but not in your main recordset.

To determine the names of columns not in the recordset (Columns-to-Bind-Dynamically)

  1. Build a list (Bound-Recordset-Columns) of the columns already bound in your main recordset.

    One approach is to create Bound-Recordset-Columns at design time. You can visually examine the RFX function calls in the recordset’s DoFieldExchange function to get these names. Then set up your list as an array initialized with the names.

    For example, the illustration shows Bound-Recordset-Columns (List 2) with three elements. Bound-Recordset-Columns is missing the Phone column shown in Current-Table-Columns (List 1).

  2. Compare Current-Table-Columns and Bound-Recordset-Columns to build a list (Columns-to-Bind-Dynamically) of the columns not already bound in your main recordset.

    One approach is to loop through your list of columns in the table at run time (Current-Table-Columns) and your list of columns already bound in your recordset (Bound-Recordset-Columns) in parallel. Into Columns-to-Bind-Dynamically put any names in Current-Table-Columns that don’t appear in Bound-Recordset-Columns.

    For example, the illustration shows Columns-to-Bind-Dynamically (List 3) with one element: the Phone column found in Current-Table-Columns (List 1) but not in Bound-Recordset-Columns (List 2).

  3. Build a list of Dynamic-Column-Values (as in List 4 in the illustration) in which to store the data values corresponding to each column name stored in your list of columns to bind dynamically (Columns-to-Bind-Dynamically).

    The elements of this list play the role of new recordset field data members. They are the storage locations to which the dynamic columns are bound. For descriptions of the lists, see Lists of Columns.

Providing Storage for the New Columns

Next, set up storage locations for the columns to be bound dynamically. The idea is to provide a list element in which to store each column’s value. These storage locations parallel the recordset member variables, which store the normally bound columns.

To provide dynamic storage for new columns (Dynamic-Column-Values)

  • Build Dynamic-Column-Values, parallel to Columns-to-Bind-Dynamically, to contain the value of the data in each column.

    For example, the illustration shows Dynamic-Column-Values (List 4) with one element: a CString object containing the actual phone number for the current record: “555-1212”.

    In the most common case, Dynamic-Column-Values has elements of type CString. If you’re dealing with columns of varying data types, you’ll need a list that can contain elements of a variety of types.

The result of the preceding procedures is two main lists: Columns-to-Bind-Dynamically containing the names of columns and Dynamic-Column-Values containing the values in the columns for the current record.

Tip If the new columns aren’t all of the same data type, you might want an extra parallel list containing items that somehow define the type of each corresponding element in the column list. (You can use the values AFX_RFX_BOOL, AFX_RFX_BYTE, and so on, for this if you wish. These constants are defined in AFXDB.H.) Choose a list type based on how you represent the column data types.

Adding RFX Calls to Bind the Columns

Finally, arrange for the dynamic binding to occur by placing RFX calls for the new columns in your DoFieldExchange function.

To dynamically add RFX calls for new columns

  • In your main recordset’s DoFieldExchange member function, add code that loops through your list of new columns (Columns-to-Bind-Dynamically). In each loop, extract a column name from Columns-to-Bind-Dynamically and a result value for the column from Dynamic-Column-Values. Pass these items to an RFX function call appropriate to the data type of the column. For descriptions of the lists, see Lists of Columns.

In the common case, in your RFX_Text function calls you extract CString objects from the lists, as in the following lines of code, where Columns-to-Bind-Dynamically is a CStringList called m_listName and Dynamic-Column-Values is a CStringList called m_listValue:

RFX_Text( pFX,
            m_listName.GetNext( posName ),
            m_listValue.GetNext( posValue ));

For an example of such a loop added to DoFieldExchange, see CSections::DoFieldExchange in the file SECTIONS.CPP in the MFC Database sample DYNABIND. For more information about RFX functions, see Macros and Globals in the Class Library Reference.

Tip If the new columns are of different data types, use a switch statement in your loop to call the appropriate RFX function for each type.

When the framework calls DoFieldExchange during the Open process to bind columns to the recordset, the RFX calls for the static columns bind those columns. Then your loop repeatedly calls RFX functions for the dynamic columns.

See the complete source code in the MFC Database sample DYNABIND.

See Also Recordset: Working with Large Data Items (ODBC)


Recordset: Fetching Records in Bulk (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For information about DAO recordsets, see the article DAO Recordset.

Class CRecordset provides support for bulk row fetching, which means that multiple records can be retrieved at once during a single fetch, rather than retrieving one record at a time from the data source. You can implement bulk row fetching only in a derived CRecordset class. The process of transferring data from the data source to the recordset object is called bulk record field exchange (Bulk RFX). Note that if you are not using bulk row fetching in a CRecordset-derived class, then data is transferred via record field exchange (RFX). For more information, see the article Record Field Exchange (RFX).

This article explains:

  • How CRecordset supports bulk row fetching.

  • Some special considerations when using bulk row fetching.

  • How to implement bulk record field exchange.

How CRecordset Supports Bulk Row Fetching

Before opening your recordset object, you can define a rowset size with the SetRowsetSize member function. The rowset size specifies how many records should be retrieved during a single fetch. When bulk row fetching is implemented, the default rowset size is 25. Note that if bulk row fetching is not implemented, the rowset size remains fixed at 1.

After you have initialized the rowset size, call the Open member function. Here you must specify the CRecordset::useMultiRowFetch option of the dwOptions parameter in order to implement bulk row fetching. You can additionally set the CRecordset::userAllocMultiRowBuffers option. The bulk record field exchange mechanism uses arrays to store the multiple rows of data retrieved during a fetch. These storage buffers can be allocated automatically by the framework, or you can allocate them manually. Specifying the CRecordset::userAllocMultiRowBuffers option means that you will do the allocation.

The following table lists the member functions provided by CRecordset to support bulk row fetching.

Member Function | Description
CheckRowsetError | Virtual function that handles any errors that occur during fetching.
DoBulkFieldExchange | Implements bulk record field exchange. Called automatically to transfers multiple rows of data from the data source to the recordset object.
GetRowsetSize | Retrieves the current setting for the rowset size.
GetRowsFetched | Tells how many rows were actually retrieved after a given fetch. In most cases, this will be the rowset size, unless an incomplete rowset was fetched.
GetRowStatus | Returns a fetch status for a particular row within a rowset.
RefreshRowset | Refreshes the data and status of a particular row within a rowset.
SetRowsetCursorPosition | Moves the cursor to a particular row within a rowset.
SetRowsetSize | Virtual function that changes the setting for the rowset size to the specified value.

Special Considerations

Although bulk row fetching is a performance gain, certain features operate differently. Before you decide to implement bulk row fetching, consider the following:

  • The framework will automatically call the DoBulkFieldExchange member function to transfer data from the data source to the recordset object. However, data is not transferred from the recordset back to the data source. Calling the AddNew, Edit, Delete, or Update member functions will result in a failed assertion. Although CRecordset currently does not provide a mechanism for updating bulk rows of data, you can write your own functions by using the ODBC API function SQLSetPos. For an example of how to do this, see the sample DBFETCH. For more information about SQLSetPos, see the ODBC SDK Programmer’s Reference on the MSDN Library CD.

  • The member functions IsDeleted, IsFieldDirty, IsFieldNull, IsFieldNullable, SetFieldDirty, and SetFieldNull cannot be used on recordsets that implement bulk row fetching. However, you can call GetRowStatus in place of IsDeleted, and GetODBCFieldInfo in place of IsFieldNullable.

  • The Move operations will reposition your recordset by rowset. For example, suppose you open a recordset that has 100 records with an initial rowset size of 10. Open will fetch rows 1 through 10, with the current record positioned on row 1. A call to MoveNext will fetch the next rowset, not the next row. This rowset will consist of rows 11 through 20, with the current record positioned on row 11. Note that MoveNext and Move( 1 ) are not equivalent when bulk row fetching is implemented. Move( 1 ) will fetch the rowset that begins 1 row from the current record. In this example, calling Move( 1 ) after calling Open will fetch the rowset consisting of rows 2 through 11, with the current record positioned on row 2. For more information, see the Move member function.

  • Unlike record field exchange, ClassWizard does not support bulk record field exchange. This means that you must manually declare your field data members as well as manually override DoBulkFieldExchange by writing calls to the Bulk RFX functions. For more information, see the topic Record Field Exchange Functions in the Class Library Reference.

How to Implement Bulk Record Field Exchange

Bulk record field exchange transfers a rowset of data from the data source to the recordset object. The Bulk RFX functions use arrays to store this data, as well as arrays to store the length of each data item in the rowset. In your class definition you must define your field data members as pointers in order to access the arrays of data. In addition, you must define a set of pointers to access the arrays of lengths. Any parameter data members should not be declared as pointers; declaring parameter data members when using bulk record field exchange is the same as declaring them when using record field exchange. The following code shows a simple example:

class MultiRowSet : public CRecordset
{
public:
   // Field/Param Data
      // field data members
      long* m_rgID;
      LPSTR m_rgName;

      // pointers for the lengths
      // of the field data
      long* m_rgIDLengths;
      long* m_rgNameLengths;

      // input parameter data member
      CString m_strNameParam;

   .
   .
   .
}

You can either allocate these storage buffers manually, or you can have the framework do the allocation. To allocate the buffers yourself, you must specify the CRecordset::userAllocMultiRowBuffers option of the dwOptions parameter in the Open member function. Be sure to set the sizes of the arrays at least equal to the rowset size. If you wish to have the framework do the allocation, you should initialize your pointers to NULL. This is typically done in the recordset object's constructor:

MultiRowSet::MultiRowSet( CDatabase* pDB )
   : CRecordset( pDB )
{
   m_rgID = NULL;
   m_rgName = NULL;
   m_rgIDLengths = NULL;
   m_rgNameLengths = NULL;
   m_strNameParam = "";

   m_nFields = 2;
   m_nParams = 1;

   .
   .
   .
}

Finally, you must override the DoBulkFieldExchange member function. For the field data members, call the Bulk RFX functions; for any parameter data members, call the RFX functions. If you opened the recordset by passing an SQL statement or stored procedure to Open, then the order in which you make the Bulk RFX calls must correspond to the order of the columns in the recordset; similarly, the order of the RFX calls for parameters must correspond to the order of parameters in the SQL statement or stored procedure.

void MultiRowSet::DoBulkFieldExchange( CFieldExchange* pFX )
{
   // call the Bulk RFX functions
   // for field data members
   pFX->SetFieldType( CFieldExchange::outputColumn );
   RFX_Long_Bulk( pFX, _T( "[colRecID]" ),
                  &m_rgID, &m_rgIDLengths );
   RFX_Text_Bulk( pFX, _T( "[colName]" ),
                  &m_rgName, &m_rgNameLengths, 30 );

   // call the RFX functions for
   // for parameter data members
   pFX->SetFieldType( CFieldExchange::inputParam );
   RFX_Text( pFX, "NameParam", m_strNameParam );
}

Important You must call the Close member function before your derived CRecordset class goes out of scope. This ensures that any memory allocated by the framework will be freed. Note that it is good programming practice to always explicitly call Close, regardless of whether you have implemented bulk row fetching.

For an additional example of implementing bulk record field exchange, see the MFC sample DBFETCH. For more information about record field exchange (RFX), see the article Record Field Exchange: How RFX Works. For more information about using parameters, see CFieldExchange::SetFieldType and the article Recordset: Parameterizing a Recordset (ODBC).

See Also CRecordset::m_nFields, CRecordset::m_nParams


Recordset: Working with Large Data Items (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to both the MFC ODBC classes and the MFC DAO classes.

Note If you’re using the MFC DAO classes, manage your large data items with class CByteArray rather than class CLongBinary. If you're using the MFC ODBC classes with bulk row fetching, use CLongBinary rather than CByteArray. For more information about bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

Suppose your database can store large pieces of data, such as bitmaps (employee photographs, maps, pictures of products, OLE objects, and so on). This kind of data is often referred to as a Binary Large Object (or BLOB) because:

  • Each field value is large.

  • Unlike numbers and other simple data types, it has no predictable size.

  • The data is formless from the perspective of your program.

This article explains what support the database classes provide for working with such objects.

Managing Large Objects

Recordsets have two ways to solve the special difficulty of managing binary large objects. You can use class CByteArray, or you can use class CLongBinary. In general, CByteArray is the preferred way to manage large binary data.

CByteArray requires more overhead than CLongBinary but is more capable, as described in The CByteArray Class. CLongBinary is described briefly in The CLongBinary Class.

For detailed information about using CByteArray to work with large data items, see Technical Note 45.

The CByteArray Class

CByteArray is one of the MFC collection classes. A CByteArray object stores a dynamic array of bytes — the array can grow if needed. The class provides fast access by index, as with built-in C++ arrays. CByteArray objects can be serialized and dumped for diagnostic purposes. The class supplies member functions for getting and setting specified bytes, inserting and appending bytes, and removing one byte or all bytes. These facilities make parsing the binary data easier. For example, if the binary object is an OLE object, you might have to work through some header bytes to reach the actual object.

Using CByteArray in Recordsets

By giving a field data member of your recordset the type CByteArray, you provide a fixed base from which RFX can manage the transfer of such an object between your recordset and the data source and through which you can manipulate the data inside the object. RFX needs a specific site for retrieved data, and you need a way to access the underlying data.

For detailed information about using CByteArray to work with large data items, see Technical Note 45.

The CLongBinary Class

A CLongBinary object is a simple shell around an HGLOBAL handle to a block of storage allocated on the heap. When it binds a table column containing a binary large object, RFX allocates the HGLOBAL handle when it needs to transfer the data to the recordset and stores the handle in the CLongBinary field of the recordset.

In turn, you use the HGLOBAL handle, m_hData, to work with the data itself, operating on it as you would on any handle data. This is where CByteArray adds capabilities.

Caution CLongBinary objects can’t be used as parameters in function calls. In addition, their implementation, which calls ::SQLGetData, necessarily slows scrolling performance for a scrollable snapshot. This may also be true when you use an ::SQLGetData call yourself to retrieve dynamic schema columns.

See Also Recordset: Obtaining SUMs and Other Aggregate Results (ODBC), Record Field Exchange


Recordset: Obtaining SUMs and Other Aggregate Results (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains how to obtain aggregate results using the following SQL keywords:

  • SUM Calculates the total of the values in a column with a numeric data type.

  • MIN Extracts the smallest value in a column with a numeric data type.

  • MAX Extracts the largest value in a column with a numeric data type.

  • AVG Calculates an average value of all the values in a column with a numeric data type.

  • COUNT Counts the number of records in a column of any data type.

You use these SQL functions to obtain statistical information about the records in a data source rather than to extract records from the data source. The recordset that is created usually consists of a single record (if all columns are aggregates) that contains a value. (There might be more than one record if you used a GROUP BY clause.) This value is the result of the calculation or extraction performed by the SQL function.

Tip To add an SQL GROUP BY clause (and possibly a HAVING clause) to your SQL statement, append it to the end of m_strFilter. For example:

m_strFilter = "sales > 10 GROUP BY SALESPERSON_ID";

You can limit the number of records you use to obtain aggregate results by filtering and sorting the columns.

Caution Some aggregation operators return a different data type from the column(s) over which they are aggregating.

  • SUM and AVG may return the next larger data type (for example, calling with int returns LONG or double).

  • COUNT usually returns LONG regardless of target column type.

  • MAX and MIN return the same data type as the columns they calculate.

For example, ClassWizard creates long m_lSales to accommodate a Sales column, but you’ll need to replace this with a double m_dblSumSales data member to accommodate the aggregate result. See the example that follows.

To obtain an aggregate result for a recordset

  1. Create a recordset containing the column(s) from which you want to obtain aggregate results.

  2. Modify the DoFieldExchange function for the recordset. Replace the string representing the column name (the second argument of the RFX function call(s)) with a string representing the aggregation function on the column. For example, replace
    RFX_Long(pFX, "Sales", m_lSales);

    with

    RFX_Double(pFX, "Sum(Sales)", m_dblSumSales)
  3. Open the recordset. The result of the aggregation operation will be left in m_dblSumSales.

Note ClassWizard actually assigns data member names without Hungarian prefixes. For example, the wizard would produce m_Sales for a Sales column, rather than the m_lSales name used earlier for illustration.

If you’re using a CRecordView class to view the data, you’ll have to change the DDX function call to display the new data member value; in this case, changing it from

DDX_FieldText(pDX, IDC_SUMSALES, m_pSet->m_lSales, m_pSet);

to

DDX_FieldText(pDX, IDC_SUMSALES, m_pSet->m_dblSumSales, m_pSet);

See Also Recordset: How Recordsets Select Records (ODBC)


Recordset: How Recordsets Select Records (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains:

  • Your role and your options in selecting records.

  • How a recordset constructs its SQL statement and selects records.

  • What you can do to customize the selection.

Recordsets select records from a data source through an ODBC driver by sending SQL statements to the driver. The SQL sent depends on how you design and open your recordset class.

Your Options in Selecting Records

The following table shows your options in selecting records.

How and When You Can Affect a Recordset

When you ... | You can ...
Declare your recordset class with ClassWizard... Specify which table to select from.

Specify which columns to include.

See ClassWizard: Creating a Recordset Class.

Complete your recordset class implementation... | Override member functions such as OnSetOptions (advanced) to set application-specific options or to change defaults. Specify parameter data members if you want a parameterized recordset.
Construct a recordset object (before you call Open) and then... Specify a search condition (possibly compound) for use in a WHERE clause that filters the records. See Recordset: Filtering Records (ODBC).

Specify a sort order for use in an ORDER BY clause that sorts the records. See Recordset: Sorting Records (ODBC).

Specify parameter values for any parameters you added to the class. See Recordset: Parameterizing a Recordset (ODBC).

Run the recordset’s query by calling Open... | Specify a custom SQL string to replace the default SQL string set up by ClassWizard. See CRecordset::Open in the Class Library Reference and SQL: Customizing Your Recordset’s SQL Statement (ODBC).
Call Requery to requery the recordset with the latest values on the data source... | Specify new parameters, filter, or sort. See Recordset: Requerying a Recordset (ODBC).

How a Recordset Constructs Its SQL Statement

When you call a recordset object’s Open member function, Open constructs an SQL statement using some or all of the following ingredients:

  • The lpszSQL parameter passed to Open. If not NULL, this parameter specifies a custom SQL string, or part of one. The framework parses the string. If the string is an SQL SELECT statement or an ODBC CALL statement, the framework uses the string as the recordset’s SQL statement. If the string does not begin with “SELECT” or “{CALL”, the framework uses what’s supplied to construct an SQL FROM clause.

  • The string returned by GetDefaultSQL. By default, this is the name of the table you specified for the recordset in ClassWizard, but you can change what the function returns. The framework calls GetDefaultSQL — if the string doesn’t begin with “SELECT” or “{CALL”, it is assumed to be a table name, which is used to construct an SQL string.

  • The field data members of the recordset, which are to be bound to specific columns of the table. The framework binds record columns to the addresses of these members, using them as buffers. The framework determines the correlation of field data members to table columns from the RFX or Bulk RFX function calls in the recordset’s DoFieldExchange or DoBulkFieldExchange member function.

  • The filter for the recordset, if any, contained in the m_strFilter data member. The framework uses this string to construct an SQL WHERE clause.

  • The sort order for the recordset, if any, contained in the m_strSort data member. The framework uses this string to construct an SQL ORDER BY clause.

    Tip To use the SQL GROUP BY clause (and possibly the HAVING clause), append the clause(s) to the end of your filter string.

  • The values of any parameter data members you specify for the class. You set parameter values just before you call Open or Requery. The framework binds the parameter values to “?” placeholders in the SQL string. At compile time, you specify the string with placeholders. At run time, the framework fills in the details based on the parameter values you pass.

Open constructs an SQL SELECT statement from these ingredients. See Customizing the Selection for details about how the framework uses the ingredients.

After constructing the statement, Open sends the SQL to the ODBC Driver Manager (and the ODBC Cursor Library if it is in memory), which sends it on to the ODBC driver for the specific DBMS. The driver communicates with the DBMS to carry out the selection on the data source and fetches the first record. The framework loads the record into the field data members of the recordset.

You can use a combination of these techniques to open tables and to construct a query based on a join of multiple tables. With additional customization, you can call predefined queries (stored procedures), select table columns not known at design time and bind them to recordset fields, or perform most other data-access tasks. Tasks you can’t accomplish by customizing recordsets can still be accomplished by calling ODBC API functions or directly executing SQL statements with CDatabase::ExecuteSQL.

Customizing the Selection

Besides supplying a filter, a sort order, or parameters, you can take the following actions to customize your recordset’s selection:

  • Pass a custom SQL string in lpszSQL when you call Open for the recordset. Anything you pass in lpsqSQL takes precedence over what the GetDefaultSQL member function returns.

    See the article SQL: Customizing Your Recordset’s SQL Statement (ODBC). That article describes the kinds of SQL statements (or partial statements) you can pass to Open and what the framework does with them.

    Note If the custom string you pass does not begin with “SELECT” or “{CALL”, MFC assumes it contains a table name. This also applies to the next bulleted item below.

  • Alter the string that ClassWizard writes in your recordset’s GetDefaultSQL member function. Edit the function’s code to change what it returns. By default, ClassWizard writes a GetDefaultSQL function that returns a single table name.

    You can have GetDefaultSQL return any of the items that you can pass in the lpszSQL parameter to Open. If you don’t pass a custom SQL string in lpszSQL, the framework uses the string that GetDefaultSQL returns. At a minimum, GetDefaultSQL must return a single table name. But you can have it return multiple table names, a full SELECT statement, an ODBC CALL statement, and so on. For a list of what you can pass to lpszSQL — or have GetDefaultSQL return — see the article SQL: Customizing Your Recordset’s SQL Statement (ODBC).

    If you’re performing a join of two or more tables, rewrite GetDefaultSQL to customize the table list used in the SQL FROM clause. See the article Recordset: Performing a Join (ODBC).

  • Manually bind additional field data members, perhaps based on information you obtain about the schema of your data source at run time. You add field data members to the recordset class, RFX or Bulk RFX function calls for them to the DoFieldExchange or DoBulkFieldExchange member function, and initializations of the data members in the class constructor.

    See the article Recordset: Dynamically Binding Data Columns (ODBC).

  • Override recordset member functions, such as OnSetOptions, to set application-specific options or to override defaults.

If you want to base the recordset on a complex SQL statement, you’ll need to use some combination of these customization techniques. For example, perhaps you want to use SQL clauses and keywords not directly supported by recordsets, or perhaps you’re joining multiple tables.

See Also Recordset: How Recordsets Update Records (ODBC), ODBC, SQL, Recordset: Locking Records (ODBC)


Recordset: How Recordsets Update Records (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

Besides their ability to select records from a data source, recordsets can (optionally) update or delete the selected records or add new records. Three factors determine a recordset’s updatability: whether the connected data source is updatable, the options you specify when you create a recordset object, and the SQL that is created.

Note The SQL upon which your CRecordset object is based can affect your recordset’s updatability. For example, if your SQL contains a join or a GROUP BY clause, MFC sets the updatability to FALSE.

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

This article explains:

  • Your role in recordset updating and what the framework does for you.

  • The recordset as an edit buffer and the differences between dynasets and snapshots.

The article Recordset: How AddNew, Edit, and Delete Work (ODBC) describes the actions of these functions from the point of view of the recordset.

The article Recordset: More About Updates (ODBC) completes the recordset update story by explaining how transactions affect updates, how closing a recordset or scrolling affects updates in progress, and how your updates interact with the updates of other users.

Your Role in Recordset Updating

The following table shows your role in using recordsets to add, edit, or delete records, along with what the framework does for you.

Recordset Updating: You and the Framework

You... | The framework...
Determine whether the data source is updatable (or appendable). | Supplies CDatabase member functions for testing the data source’s updatability or appendability.
Open an updatable recordset (of any type). |
Determine whether the recordset is updatable by calling CRecordset update functions such as CanUpdate or CanAppend. |
Call recordset member functions to add, edit, and delete records. | Manages the mechanics of exchanging data between your recordset object and the data source.
Optionally, use transactions to control the update process. | Supplies CDatabase member functions to support transactions.

For more information about transactions, see the article Transaction (ODBC).

The Edit Buffer

Taken collectively, the field data members of a recordset serve as an edit buffer that contains one record — the current record. Update operations use this buffer to operate on the current record.

  • When you add a record, the edit buffer is used to build a new record. When you finish adding the record, the record that was previously current becomes current again.

  • When you update (edit) a record, the edit buffer is used to set the field data members of the recordset to new values. When you finish updating, the updated record is still current.

When you call AddNew or Edit, the current record is stored so it can be restored later as needed. When you call Delete, the current record is not stored but is marked as deleted, and you must scroll to another record.

Note The edit buffer plays no role in record deletion. When you delete the current record, the record is marked as deleted, and the recordset is “not on a record” until you scroll to a different record.

Dynasets and Snapshots

Dynasets refresh a record’s contents as you scroll to the record. Snapshots are static representations of the records, so a record’s contents are not refreshed unless you call Requery. To use all the functionality of dynasets, you must be working with an ODBC driver that conforms to the correct level of ODBC API support. For more information, see the articles ODBC and Dynaset.

See Also Recordset: How AddNew, Edit, and Delete Work (ODBC)


Recordset: How AddNew, Edit, and Delete Work (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains how the AddNew, Edit, and Delete member functions of class CRecordset work. Topics covered include:

  • How adding records works

  • Visibility of added records

  • How editing records works

  • How deleting records works

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If you are using bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

As a supplement, you might want to read the article Record Field Exchange: How RFX Works, which describes the corresponding role of RFX in update operations.

Adding a Record

Adding a new record to a recordset involves calling the recordset’s AddNew member function, setting the values of the new record’s field data members, and calling the Update member function to write the record to the data source.

As a precondition for calling AddNew, the recordset must not have been opened as read-only. The CanUpdate and CanAppend member functions let you determine these conditions.

When you call AddNew:

  1. The record in the edit buffer is stored, so its contents can be restored if the operation is canceled.

  2. The field data members are flagged so it will be possible to detect changes in them later. The field data members are also marked “clean” (unchanged) and set to a Null.

After you call AddNew, the edit buffer represents a new, empty record, ready to be filled in with values. To do this, you manually set the values by assigning to them. Instead of specifying an actual data value for a field, you can call SetFieldNull to specify the value Null.

To commit your changes, you call Update.

When you call Update for the new record:

  • If your ODBC driver supports the ::SQLSetPos ODBC API function, MFC uses the function to add the record on the data source. With ::SQLSetPos, MFC can add a record more efficiently because it doesn’t have to construct and process an SQL statement.

  • If ::SQLSetPos can’t be used, MFC does the following:
  1. If no changes are detected, Update does nothing and returns 0.

  2. If there are changes, Update constructs an SQL INSERT statement. The columns represented by all dirty field data members are listed in the INSERT statement. To force a column to be included, call the SetFieldDirty member function:
    SetFieldDirty( &m_dataMember, TRUE );
  3. Update commits the new record — the INSERT statement is executed and the record is committed to the table on the data source (and the recordset, if not a snapshot) unless a transaction is in progress (see How Transactions Affect Updates in the article Recordset: More About Updates).

  4. The stored record is restored to the edit buffer. The record that was current before the AddNew call is current again regardless of whether the INSERT statement was successfully executed.

Tip For complete control of a new record, take the following approach: (a) set the values of any fields that will have values; (b) explicitly set any fields that will remain Null by calling SetFieldNull with a pointer to the field and the parameter TRUE (the default). If you want to ensure that a field is not written to the data source, call SetFieldDirty with a pointer to the field and the parameter FALSE, and do not modify the field’s value. To determine whether a field is allowed to be Null, call IsFieldNullable.

Tip Advanced: To detect when recordset data members change value, MFC uses a PSEUDO_NULL value appropriate to each data type that you can store in a recordset. If you must explicitly set a field to the PSEUDO_NULL value and the field happens already to be marked Null, you must also call SetFieldNull, passing the address of the field in the first parameter and FALSE in the second parameter.

Visibility of Added Records

When is an added record visible to your recordset? Added records sometimes show up and sometimes aren’t visible, depending on two things:

  • What your driver is capable of.

  • What the framework can take advantage of.

If your ODBC driver supports the ::SQLSetPos ODBC API function, MFC uses the function to add records. With ::SQLSetPos, added records are visible to any updatable MFC recordset. Without support for the function, added records are not visible, and you must call Requery to see them. Using ::SQLSetPos is also more efficient.

Editing an Existing Record

Editing an existing record in a recordset involves scrolling to the record, calling the recordset’s Edit member function, setting the values of the new record’s field data members, and calling the Update member function to write the changed record to the data source.

As a precondition for calling Edit, the recordset must be updatable and on a record. The CanUpdate and IsDeleted member functions let you determine these conditions. The current record also must not already have been deleted, and there must be records in the recordset (both IsBOF and IsEOF return 0).

When you call Edit, the record in the edit buffer (the current record) is stored. The stored record’s values are later used to detect whether any fields have changed.

After you call Edit, the edit buffer still represents the current record but is now ready to accept changes to the field data members. To change the record, you manually set the values of any field data members you want to edit. Instead of specifying an actual data value for a field, you can call SetFieldNull to specify the value Null. To commit your changes, call Update.

Tip To get out of AddNew or Edit mode, call Move with the parameter AFX_MOVE_REFRESH.

As a precondition for calling Update, the recordset must not be empty and the current record must not have been deleted. IsBOF, IsEOF, and IsDeleted should all return 0.

When you call Update for the edited record:

  • If your ODBC driver supports the ::SQLSetPos ODBC API function, MFC uses the function to update the record on the data source. With ::SQLSetPos, the driver compares your edit buffer with the corresponding record on the server, updating the record on the server if the two are different. With ::SQLSetPos, MFC can update a record more efficiently because it doesn’t have to construct and process an SQL statement.

    -or-

  • If ::SQLSetPos can’t be used, MFC does the following:
  1. If there have been no changes, Update does nothing and returns 0.

  2. If there are changes, Update constructs an SQL UPDATE statement. The columns listed in the UPDATE statement are based on the field data members that have changed.

  3. Update commits the changes — executes the UPDATE statement — and the record is changed on the data source, but not committed if a transaction is in progress (see the article Transaction: Performing a Transaction in a Recordset (ODBC) for details about how the transaction affects the update). ODBC keeps a copy of the record, which also changes.

  4. Unlike the process for AddNew, the Edit process does not restore the stored record. The edited record remains in place as the current record.

Caution When you prepare to update a recordset by calling Update, take care that your recordset includes all columns making up the primary key of the table (or all of the columns of any unique index on the table, or enough columns to uniquely identify the row). In some cases, the framework can use only the columns selected in your recordset to identify which record in your table to update. Without all the necessary columns, multiple records may be updated in the table. In this case, the framework will throw exceptions when you call Update.

Tip If you call AddNew or Edit after having called either function previously but before you call Update, the edit buffer is refreshed with the stored record, replacing the new or edited record in progress. This behavior gives you a way to abort an AddNew or Edit and begin a new one: if you determine that the record-in-progress is faulty, simply call Edit or AddNew again.

Deleting a Record

Deleting a record from a recordset involves scrolling to the record and calling the recordset’s Delete member function. Unlike AddNew and Edit, Delete does not require a matching call to Update.

As a precondition for calling Delete, the recordset must be updatable and it must be on a record. The CanUpdate, IsBOF, IsEOF, and IsDeleted member functions let you determine these conditions.

When you call Delete:

  • If your ODBC driver supports the ::SQLSetPos ODBC API function, MFC uses the function to delete the record on the data source. Using ::SQLSetPos is usually more efficient than using SQL.

    -or-

  • If ::SQLSetPos can’t be used, MFC does the following:
  1. The current record in the edit buffer is not backed up as in AddNew and Edit.

  2. Delete constructs an SQL DELETE statement that will remove the record.

    The current record in the edit buffer is not stored as in AddNew and Edit.

  3. Delete commits the deletion — executes the DELETE statement. The record is marked deleted on the data source and, if the record is a snapshot, in ODBC.

  4. The deleted record’s values are still in the field data members of the recordset, but the field data members are marked Null and the recordset’s IsDeleted member function will return a nonzero value.

Important After deleting a record, you should scroll to another record to refill the edit buffer with the new record’s data. It’s an error to call Delete again, or to call Edit.

For information about the SQL statements used in update operations, see the article SQL.

See Also Recordset: More About Updates (ODBC), Record Field Exchange


Recordset: More About Updates (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. For DAO recordsets, see the article DAO Recordset.

This article explains:

  • How other operations, such as transactions, affect updates.

  • Your updates and those of other users.

  • More about the Update and Delete member functions.

Note This article applies to objects derived from CRecordset in which bulk row fetching has not been implemented. If you have implemented bulk row fetching, some of the information does not apply. For example, you cannot call the AddNew, Edit, Delete, and Update member functions; however, you can perform transactions. For more information about bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

How Other Operations Affect Updates

Your updates are affected by transactions in effect at the time of the update, by closing the recordset before completing a transaction, and by scrolling before completing a transaction.

How Transactions Affect Updates

Beyond understanding how AddNew, Edit, and Delete work, it’s important to understand how the BeginTrans, CommitTrans, and Rollback member functions of CDatabase work with the update functions of CRecordset.

By default, calls to AddNew and Edit affect the data source immediately when you call Update. Delete calls take effect immediately. But you can establish a transaction and execute a batch of such calls. The updates are not permanent until you commit them. If you change your mind, you can roll back the transaction instead of committing it.

For more information about transactions, see the article Transaction (ODBC).

How Closing the Recordset Affects Updates

If you close a recordset, or its associated CDatabase object, with a transaction in progress (you haven’t called CommitTrans or Rollback), the transaction is rolled back automatically (unless your database backend is the Microsoft Jet database engine). How Rollback Affects Transactions in the article Transaction: How Transactions Affects Updates (ODBC) describes the effect this has on AddNew, Edit, or Delete operations in progress.

Caution If you are using the Microsoft Jet database engine, closing a recordset inside an explicit transaction does not result in releasing any of the rows that were modified or locks that were placed until the explicit transaction is committed or rolled back. It is recommended that you always both open and close recordsets either inside or outside of an explicit Jet transaction.

How Scrolling Affects Updates

When you scroll in a recordset, the edit buffer is filled with each new current record (the previous record is not stored first). Scrolling skips over records previously deleted. If you scroll after an AddNew or Edit call without calling Update, CommitTrans, or Rollback first, any changes are lost (with no warning to you) as a new record is brought into the edit buffer. The edit buffer is filled with the record scrolled to, the stored record is freed, and no change occurs on the data source. This applies to both AddNew and Edit.

Your Updates and the Updates of Other Users

When you use a recordset to update data, your updates affect other users. Similarly, the updates of other users during the lifetime of your recordset affect you.

In a multiuser environment, other users can open recordsets that contain some of the same records you have selected in your recordset. Changes to a record before you retrieve it are reflected in your recordset. Dynasets retrieve a record each time you scroll to it, so dynasets reflect changes each time you scroll to a record. Snapshots retrieve a record the first time you scroll to it, so snapshots reflect only those changes that occur before you scroll to the record initially.

Records added by other users after you open the recordset don’t show up in your recordset unless you requery. If your recordset is a dynaset, edits to existing records by other users do show up in your dynaset when you scroll to the affected record. If your recordset is a snapshot, edits don’t show up until you requery the snapshot. If you want to see records added or deleted by other users in your snapshot, or records added by other users in your dynaset, call Requery to rebuild the recordset. (Note that the deletions of other users show up in your dynaset.) You may also call Requery to see records you add, but not to see your deletions.

Tip To force caching of an entire snapshot at once, call MoveLast immediately after you open the snapshot. Then call MoveFirst to begin working with the records. MoveLast is equivalent to scrolling over all the records, but it retrieves them all at once. Note, however, that this can lower performance and may not be required for some drivers.

The effects of your updates on other users are similar to their effects on you.

More About Update and Delete

This section provides additional information to help you work with Update and Delete.

Update Success and Failure

If Update succeeds, the AddNew or Edit mode ends. To begin an AddNew or Edit mode again, call AddNew or Edit.

If Update fails (returns FALSE or throws an exception), you remain in AddNew or Edit mode, depending on which function you called last. You can then do one of the following:

  • Modify a field data member and try the Update again.

  • Call AddNew to reset the field data members to Null, set the values of the field data members, then call Update again.

  • Call Edit to reload the values that were in the recordset before the first call to AddNew or Edit, then set the values of the field data members, then call Update again. After a successful Update call (except after an AddNew call), the field data members retain their new values.

  • Call Move (including Move with a parameter of AFX_MOVE_REFRESH, or 0), which flushes any changes and ends any AddNew or Edit mode in effect.

Update and Delete

This section applies to both Update and Delete.

On an Update or Delete operation, one and only one record should be updated. That record is the current record, which corresponds to the data values in the fields of the recordset. If for some reason no records are affected or more than one record is affected, an exception is thrown containing one of the following RETCODE values:

  • AFX_SQL_ERROR_NO_ROWS_AFFECTED

  • AFX_SQL_ERROR_MULTIPLE_ROWS_AFFECTED

When these exceptions are thrown, you remain in the AddNew or Edit state you were in when you called Update or Delete. Here are the most common scenarios in which you would see these exceptions. You’re most likely to see:

  • AFX_SQL_ERROR_NO_ROWS_AFFECTED when you’re using optimistic locking mode and another user has modified the record in a way that prevents the framework from identifying the correct record to update or delete.

  • AFX_SQL_ERROR_MULTIPLE_ROWS_AFFECTED when the table you’re updating has no primary key or unique index, and you don’t have enough columns in the recordset to uniquely identify a table row.

See Also Recordset: How Recordsets Select Records (ODBC), Record Field Exchange, SQL, Exceptions: Database Exceptions


SQL

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Structured Query Language (SQL) is a way to communicate with a relational database that lets you define, query, modify, and control the data. Using SQL syntax, you can construct a statement that extracts records according to criteria you specify.

Note This information applies to the MFC ODBC classes. If you’re working with the MFC DAO classes, see the topic Comparison of Microsoft Jet Database Engine SQL and ANSI SQL in DAO Help.

SQL statements begin with a keyword “verb” such as CREATE or SELECT. SQL is a very powerful language; a single statement can affect an entire table.

Many versions of SQL exist, each developed with a particular DBMS in mind. The MFC database classes recognize a set of SQL statements that corresponds to the X/Open and SQL Access Group Common Applications Environment (CAE) SQL draft specification (1991). For details on the syntax of these statements, see Appendix C in the ODBC SDK Programmer’s Reference on the MSDN Library CD.

This article explains:

  • The relationship between ODBC and SQL.

  • The most common SQL keywords used by the database classes.

  • How the database classes use SQL.

Open Database Connectivity (ODBC)

The database classes are implemented with ODBC, which uses SQL in a call-level interface rather than embedding SQL commands in the code. ODBC uses SQL to communicate with a data source through ODBC drivers. These drivers interpret the SQL and translate it, if necessary, for use with a particular database format, such as Microsoft Access. For more information about how ODBC uses SQL, see the article ODBC and the ODBC SDK Programmer’s Reference on the MSDN Library CD.

The Database Classes

The database classes are designed to let you manipulate and update data in an existing data source. ClassWizard and the database classes construct most of the SQL statements for you.

The database classes use a portion of SQL known as the Data Manipulation Language (DML). These commands let you work with all or part of the data source, add new records, edit records, and delete records. The following table lists the most common SQL keywords and the ways the database classes use them.

Some Common SQL Keywords

SQL keyword | ClassWizard and database classes use it ...
SELECT | To identify which tables and columns in the data source are to be used.
WHERE | To apply a filter that narrows the selection.
ORDER BY | To apply a sort order to the recordset.
INSERT | To add new records to a recordset.
DELETE | To delete records from a recordset.
UPDATE | To modify the fields of a record.

In addition, the database classes recognize ODBC CALL statements, which you can use to call a predefined query (or stored procedure) on some data sources. The ODBC database driver interprets these statements and substitutes the command appropriate for each DBMS.

Note Not all DBMSs support CALL statements.

If the classes cannot recognize a user-supplied statement in CRecordset::Open, it is interpreted as a table name.

For an explanation of how the framework constructs SQL statements, see the articles Recordset: How Recordsets Select Records (ODBC) and SQL: Customizing Your Recordset’s SQL Statement (ODBC).

SQL databases use data types similar to those used in C and C++. For a discussion of these similarities, see the article SQL: SQL and C++ Data Types (ODBC).

You can find more information about SQL, including a list of supported SQL statements, data types, SQL core grammar, and a reading list of recommended publications about SQL, in the ODBC SDK Programmer's Reference on the MSDN Library CD.

How the Database Classes Use SQL

The recordsets you derive from the database classes use ODBC to communicate with a data source, and ODBC retrieves records from the data source by sending SQL statements. This article explains the relationship between the database classes and SQL.

A recordset constructs an SQL statement by building up the pieces of an SQL statement into a CString. The string is constructed as a SELECT statement, which returns a set of records.

When the recordset calls ODBC to send an SQL statement to the data source, the ODBC Driver Manager passes the statement to the ODBC driver, and the driver sends it to the underlying DBMS. The DBMS returns a result set of records, and the ODBC driver returns the records to the application. The database classes let your program access the result set in a type-safe C++ class derived from CRecordset.

The following articles provide more information about how the database classes use SQL:

  • SQL: Customizing Your Recordset’s SQL Statement (ODBC)

  • SQL: SQL and C++ Data Types (ODBC)

  • SQL: Making Direct SQL Calls (ODBC)

See Also ODBC


SQL: Customizing Your Recordset's SQL Statement (ODBC)

SQL: Customizing Your Recordset’s SQL Statement (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains:

  • How the framework constructs an SQL statement.

  • How to override the SQL statement.

Note This information applies to the MFC ODBC classes. If you’re working with the MFC DAO classes, see the topic Comparison of Microsoft Jet Database Engine SQL and ANSI SQL in DAO Help.

SQL Statement Construction

Your recordset bases record selection primarily on an SQL SELECT statement. When you declare your class with ClassWizard, the wizard writes an overriding version of the GetDefaultSQL member function that looks something like this (for a recordset class called CAuthors).

CString CAuthors::GetDefaultSQL()
{
    return "AUTHORS";
}

By default, this override returns the table name you specified with ClassWizard — in the example, the table name is “AUTHORS.” When you later call the recordset’s Open member function, Open constructs a final SELECT statement of the form:

SELECT rfx-field-list FROM table-name [WHERE m_strFilter]
       [ORDER BY m_strSort]

where table-name is obtained by calling GetDefaultSQL and rfx-field-list is obtained from the RFX function calls in DoFieldExchange. This is what you get for a SELECT statement unless you replace it with an overriding version at run time, although you can also modify the default statement with parameters or a filter.

Important If you specify a column name that contains (or could contain) spaces, you must enclose the name in square brackets. For example, the name “First Name” should be “[First Name]”.

To override the default SELECT statement, pass a string containing a complete SELECT statement when you call Open. Instead of constructing its own default string, the recordset uses the string you supply. If your replacement statement contains a WHERE clause, don’t specify a filter in m_strFilter because you would then have two filter statements. Similarly, if your replacement statement contains an ORDER BY clause, don’t specify a sort in m_strSort so that you will not have two sort statements.

Caution In the ENROLL tutorial application, filter strings typically use a parameter placeholder, “?”, rather than assigning a specific literal value, such as “MATH101”, at compile time. If you do use literal strings in your filters (or other parts of the SQL statement), you may have to “quote” (enclose in specified delimiters) such strings with a DBMS-specific literal prefix and literal suffix character (or characters). For example, the code in the ENROLL tutorial uses a single quote character to bracket the value “MATH101” assigned as the filter.

You may also encounter special syntactic requirements for operations such as outer joins, depending on your DBMS. Use ODBC functions to obtain this information from your driver for the DBMS. For example, call ::SQLGetTypeInfo for a particular data type, such as SQL_VARCHAR, to request the LITERAL_PREFIX and LITERAL_SUFFIX characters. If you are writing database-independent code, see Appendix C in the ODBC SDK Programmer’s Reference on the MSDN Library CD for detailed syntax information.

A recordset object constructs the SQL statement that it uses to select records unless you pass a custom SQL statement. How this is done depends mainly on the value you pass in the lpszSQL parameter of the Open member function.

The general form of an SQL SELECT statement is:

SELECT [ALL | DISTINCT] column-list FROM table-list
    [WHERE search-condition][ORDER BY column-list [ASC | DESC]]

One way to add the DISTINCT keyword to your recordset’s SQL statement is to embed the keyword in the first RFX function call in DoFieldExchange. For example:

...
    RFX_Text(pFX, "DISTINCT CourseID", m_strCourseID);
...

Warning Use this technique only with a recordset opened as read-only.

Overriding the SQL Statement

The following table shows the possibilities for the lpszSQL parameter to Open. The cases in the table are explained following the table.

The lpszSQL Parameter and the Resulting SQL String

Case | What you pass in lpszSQL | The resulting SELECT statement
1 | NULL | SELECT rfx-field-list FROM table-name CRecordset::Open calls GetDefaultSQL to get the table name. The resulting string is one of Cases 2 through 5, depending on what GetDefaultSQL returns.
2 | A table name | SELECT rfx-field-list FROM table-name The field list is taken from the RFX statements in DoFieldExchange. If m_strFilter and m_strSort are not empty, adds the WHERE and/or ORDER BY clauses.
3 * | A complete SELECT statement but without a WHERE or ORDER BY clause | As passed. If m_strFilter and m_strSort are not empty, adds the WHERE and/or ORDER BY clauses.
4 * | A complete SELECT statement with a WHERE and/or ORDER BY clause | As passed. m_strFilter and/or m_strSort must remain empty, or two filter and/or sort statements will be produced.
5 * | A call to a stored procedure | As passed.

* m_nFields must be less than or equal to the number of columns specified in the SELECT statement. The data type of each column specified in the SELECT statement must be the same as the data type of the corresponding RFX output column.

Case 1 lpszSQL = NULL

The recordset selection depends on what GetDefaultSQL returns when CRecordset::Open calls it. Cases 2 through 5 describe the possible strings.

Case 2 lpszSQL = a Table Name

The recordset uses record field exchange (RFX) to build the column list from the column names provided in the RFX function calls in the recordset class’s override of DoFieldExchange. If you used ClassWizard to declare your recordset class, this case has the same result as Case 1 (provided that you pass the same table name you specified in ClassWizard). If you don’t use ClassWizard to write your class, Case 2 is the simplest way to construct the SQL statement.

The following example constructs an SQL statement that selects records from the MFC tutorial sample ENROLL. When the framework calls the GetDefaultSQL member function, the function returns the name of the table, SECTION.

CString CEnrollSet::GetDefaultSQL()
{
    return "SECTION";
}

To obtain the names of the columns for the SQL SELECT statement, the framework calls the DoFieldExchange member function.

void CEnrollSet::DoFieldExchange(CFieldExchange* pFX)
{
    pFX->SetFieldType(CFieldExchange::outputColumn);
    //{{AFX_FIELD_MAP(CEnrollSet)
    RFX_Text(pFX, "CourseID", m_strCourseID);
    RFX_Text(pFX, "InstructorID", m_strInstructorID);
    RFX_Text(pFX, "RoomNo", m_strRoomNo);
    RFX_Text(pFX, "Schedule", m_strSchedule);
    RFX_Text(pFX, "SectionNo", m_strSectionNo);
    //}}AFX_FIELD_MAP
}

When complete, the SQL statement looks like this:

SELECT CourseID, InstructorID, RoomNo, Schedule, SectionNo
    FROM SECTION

Case 3 lpszSQL = a SELECT/FROM Statement

You specify the column list by hand rather than relying on RFX to construct it automatically. You might want to do this when:

  • You want to specify the DISTINCT keyword following SELECT.

    Your column list should match the column names and types in the same order as they are listed in DoFieldExchange.

  • You have reason to manually retrieve column values using the ODBC function ::SQLGetData rather than relying on RFX to bind and retrieve columns for you.

    You might, for example, want to accommodate new columns a customer of your application added to the database tables after the application was distributed. You need to add these extra field data members, that were not known at the time you declared the class with ClassWizard.

    Your column list should match the column names and types in the same order as they are listed in DoFieldExchange, followed by the names of the manually bound columns. The MFC Database sample CATALOG provides classes called CTable and CColumn which you can use to retrieve column information from the data source. For more information, see the article Recordset: Dynamically Binding Data Columns (ODBC) and the MFC sample CATALOG.

  • You want to join tables by specifying multiple tables in the FROM clause.

    For information and an example, see the article Recordset: Performing a Join (ODBC).

Case 4 lpszSQL = SELECT/FROM Plus WHERE and/or ORDER BY

You specify everything: the column list (based on the RFX calls in DoFieldExchange), the table list, and the contents of a WHERE and/or an ORDER BY clause. If you specify your WHERE and/or ORDER BY clauses this way, do not use m_strFilter and/or m_strSort.

Case 5 lpszSQL = a Stored Procedure Call

If you need to call a predefined query (such as a stored procedure in a Microsoft SQL Server database), you must write a CALL statement in the string you pass to lpszSQL. ClassWizard doesn’t support declaring a recordset class for calling a predefined query. Not all predefined queries return records.

If a predefined query doesn’t return records, you can use the CDatabase member function ExecuteSQL directly. For a predefined query that does return records, you must also manually write the RFX calls in DoFieldExchange for any columns the procedure returns. The RFX calls must be in the same order, and return the same types, as the predefined query. For more information, see the article Recordset: Declaring a Class for a Predefined Query (ODBC).

See Also SQL: SQL and C++ Data Types (ODBC), SQL: Making Direct SQL Calls (ODBC)


SQL: SQL and C++ Data Types (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Note This information applies to the MFC ODBC classes. If you’re working with the MFC DAO classes, see the topic Comparison of Microsoft Jet Database Engine SQL and ANSI SQL in DAO Help.

The following table maps ANSI SQL data types to C++ data types. This augments the C language information given in Appendix D of the ODBC SDK Programmer’s Reference on the MSDN Library CD. ClassWizard manages most data-type mapping for you. If you don’t use ClassWizard, you can use the mapping information to help you write the field exchange code manually.

ANSI SQL Data Types Mapped to C++ Data Types

ANSI SQL data type | C++ data type
CHAR | CString
DECIMAL | CString 1
SMALLINT | int
REAL | float
INTEGER | long
FLOAT | double
DOUBLE | double
NUMERIC | CString 1
VARCHAR | CString
LONGVARCHAR | CLongBinary, CString 2
BIT | BOOL
TINYINT | BYTE
BIGINT | CString 1
BINARY | CByteArray
VARBINARY | CByteArray
LONGVARBINARY | CLongBinary, CByteArray 3
DATE | CTime, CString
TIME | CTime, CString
TIMESTAMP | CTime, CString

1. ANSI DECIMAL and NUMERIC map to CString because SQL_C_CHAR is the default ODBC transfer type.

2. Character data beyond 255 characters is truncated by default when mapped to CString. You can extend the truncation length by explicitly setting the nMaxLength argument of RFX_Text.

3. Binary data beyond 255 characters is truncated by default when mapped to CByteArray. You can extend the truncation length by explicitly setting the nMaxLength argument of RFX_Binary.

If you are not using the ODBC cursor library, you may encounter a problem when attempting to update two or more long variable-length fields using the Microsoft SQL Server ODBC driver and the MFC ODBC database classes. The ODBC types, SQL_LONGVARCHAR and SQL_LONGVARBINARY, map to "text" and "image" SQL Server types. A CDBException will be thrown if you update two or more long variable-length fields on the same call to CRecordset::Update. Therefore, do not update multiple long columns simultaneously with CRecordset::Update. You can update multiple long columns simultaneously with the ODBC API SQLPutData. You can also use the ODBC cursor library, but this is not recommended for drivers, like the SQL Server driver, that support cursors and don’t need the cursor library.

If you are using the ODBC cursor library with the MFC ODBC database classes and the Microsoft SQL Server ODBC driver, an ASSERT may occur along with a CDBException if a call to CRecordset::Update follows a call to CRecordset::Requery. Instead, call CRecordset::Close and CRecordset::Open rather than CRecordset::Requery. Another solution is not to use the ODBC cursor library, since the SQL Server and the SQL Server ODBC driver provide native support for cursors natively and the ODBC cursor library isn’t needed.

See Also SQL: Making Direct SQL Calls (ODBC)


SQL: Making Direct SQL Calls (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains:

  • When to use direct SQL calls.

  • How you make direct SQL calls to the data source.

Note This information applies to the MFC ODBC classes. If you’re working with the MFC DAO classes, see the topic Comparison of Microsoft Jet Database Engine SQL and ANSI SQL in DAO Help.

When to Call SQL Directly

To create new tables, drop (delete) tables, alter existing tables, create indexes, and perform other SQL functions that change the data source schema, you must issue an SQL statement directly to the data source using Database Definition Language (DDL). When you use ClassWizard to create a recordset for a table — at design time — you can choose which columns of the table to represent in the recordset. This doesn’t allow for columns you or another user of the data source add to the table later, after your program has been compiled. The database classes don’t support DDL directly, but you can still write code to bind a new column to your recordset dynamically, at run time. For information on how to do this binding, see the article Recordset: Dynamically Binding Data Columns (ODBC).

You can use the DBMS itself to alter the schema, or another tool that lets you perform DDL functions.

You can also use ODBC function calls for sending SQL statements, such as calling a predefined query (stored procedure) that doesn’t return records.

Making Direct SQL Function Calls

You can directly execute an SQL call using a CDatabase object. Set up your SQL statement string (usually in a CString) and pass it to the ExecuteSQL member function of your CDatabase object. If you use ODBC function calls to send an SQL statement that normally returns records, the records are ignored.


Transaction (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article applies to the MFC ODBC classes. If you’re working with the MFC DAO classes, see the article DAO Workspace: Managing Transactions.

A transaction is a way to group, or batch, a series of updates to a data source so that all are committed at once, or none are committed if you roll back the transaction. If you do not use a transaction, changes to the data source are committed automatically rather than being committed on demand.

Note Not all ODBC database drivers support transactions. Call the CanTransact member function of your CDatabase or CRecordset object to determine whether your driver supports transactions for a given database. Note that CanTransact does not tell you whether the data source provides full transaction support. You must also call CDatabase::GetCursorCommitBehavior and CDatabase::GetCursorRollbackBehavior after CommitTrans and Rollback to check the effect of the transaction on the open CRecordset object.

Calls to the AddNew and Edit member functions of a CRecordset object affect the data source immediately when you call Update. Delete calls also take effect immediately. In contrast, you can use a transaction consisting of multiple calls to AddNew, Edit, Update, and Delete, which are performed but not committed until you call CommitTrans explicitly. By establishing a transaction, you can execute a series of such calls while retaining the ability to roll them back. If a critical resource is unavailable or some other condition prevents the entire transaction from being completed, you can roll back the transaction instead of committing it. In that case, none of the changes belonging to the transaction affect the data source.

Note Currently, class CRecordset does not support updates to the data source if you have implemented bulk row fetching. This means you cannot make calls to AddNew, Edit, Delete, or Update. However, you can write you own functions to perform updates and then call those functions within a given transaction. For an example of how to do this, see the sample DBFETCH. For more information about bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

Note Besides affecting your recordset, transactions affect SQL statements that you execute directly as long as you use the ODBC HDBC associated with your CDatabase object or an ODBC HSTMT based on that HDBC.

Transactions are particularly useful when you have multiple records that must be updated simultaneously. In this case, you want to avoid a half-completed transaction, such as might happen if an exception were thrown before the last update was made. Grouping such updates into a transaction allows a recovery (rollback) from the changes, and returns the records to the pretransaction state. For example, if a bank transfers money from account A to account B, both the withdrawal from A and the deposit to B must succeed to process the funds correctly, or the whole transaction must fail.

In the database classes, you perform transactions through CDatabase objects. A CDatabase object represents a connection to a data source, and one or more recordsets associated with that CDatabase object operate on tables of the database through recordset member functions.

Note Only one level of transactions is supported. You cannot nest transactions, nor can a transaction span multiple database objects.

The following articles provide more information about how transactions are performed:

  • Transaction: Performing a Transaction in a Recordset (ODBC)

  • Transaction: How Transactions Affect Updates (ODBC)


Transaction: Performing a Transaction in a Recordset (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

This article explains how to perform a transaction in a recordset.

Note Only one level of transactions is supported; you cannot nest transactions.

To perform a transaction in a recordset

  1. Call the CDatabase object’s BeginTrans member function.

  2. If you have not implemented bulk row fetching, call the AddNew/Update, Edit/Update, and Delete member functions of one or more recordset objects of the same database as many times as needed. See the article Recordset: Adding, Updating, and Deleting Records (ODBC). If you have implemented bulk row fetching, you must write your own functions to update the data source. For an example of how to do this, see the sample DBFETCH.

  3. Finally, call the CDatabase object’s CommitTrans member function. Or if an error occurs in one of the updates, or you decide to cancel the changes, call its Rollback member function.

The following example uses two recordsets to delete a student’s enrollment from a school registration database, removing the student from all classes in which the student is enrolled. The Delete calls in both recordsets must succeed, so a transaction is required. The example assumes the existence of m_dbStudentReg, a member variable of type CDatabase already connected to the data source, and the recordset classes CEnrollmentSet and CStudentSet. The strStudentID variable contains a value obtained from the user.

BOOL CEnrollDoc::RemoveStudent( CString strStudentID )
{
    // remove student from all the classes
    // the student is enrolled in

    if ( !m_dbStudentReg.BeginTrans( ) )
        return FALSE;

    CEnrollmentSet rsEnrollmentSet(&m_dbStudentReg);
    rsEnrollmentSet.m_strFilter = "StudentID = " + strStudentID;

    if ( !rsEnrollmentSet.Open(CRecordset::dynaset) )
        return FALSE;

    CStudentSet rsStudentSet(&m_dbStudentReg);
    rsStudentSet.m_strFilter = "StudentID = " + strStudentID;

    if ( !rsStudentSet.Open(CRecordset::dynaset) )
        return FALSE;

    TRY
    {
        while ( !rsEnrollmentSet.IsEOF( ) )
        {
            rsEnrollmentSet.Delete( );
            rsEnrollmentSet.MoveNext( );
        }

        // delete the student record
        rsStudentSet.Delete( );

        m_dbStudentReg.CommitTrans( );
    }

    CATCH_ALL(e)
    {
        m_dbStudentReg.Rollback( );
        return FALSE;
    }
    END_CATCH_ALL

    rsEnrollmentSet.Close( );
    rsStudentSet.Close( );

    return TRUE;

}

Warning Calling BeginTrans again without calling CommitTrans or Rollback is an error.

See Also Transaction: How Transactions Affect Updates (ODBC), CDatabase, CRecordset


Transaction: How Transactions Affect Updates (ODBC)

Home | Overview | How Do I | FAQ | Sample | Tutorial | ODBC Driver List

Updates to the data source are managed during transactions through the use of an edit buffer (the same method used outside of transactions). The field data members of a recordset collectively serve as an edit buffer that contains the current record, which the recordset backs up temporarily during an AddNew or Edit. During a Delete operation, the current record is not backed up within a transaction. For more information about the edit buffer and how updates store the current record, see the article Recordset: How Recordsets Update Records (ODBC).

Note If you have implemented bulk row fetching, you cannot call AddNew, Edit, or Delete. You must instead write your own functions to perform updates to the data source. For an example of how to do this, see the sample DBFETCH. For more information about bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

During transactions, AddNew, Edit, and Delete operations can be committed or rolled back. The effects of CommitTrans and Rollback may cause the current record to not be restored to the edit buffer. To make sure that the current record is properly restored, it is important to understand how the CommitTrans and Rollback member functions of CDatabase work with the update functions of CRecordset.

How CommitTrans Affects Updates

The following table explains the effects of CommitTrans on transactions.

How CommitTrans Affects Updates

Operation | Status of data source
AddNew and Update, then CommitTrans | New record added to data source.
AddNew (without Update), then CommitTrans | New record is lost. Record not added to data source.
Edit and Update, then CommitTrans | Edits committed to data source.
Edit (without Update), then CommitTrans | Edits to the record are lost. Record remains unchanged on the data source.
Delete then CommitTrans | Records deleted from data source.

How Rollback Affects Transactions

The following table explains the effects of Rollback on transactions.

How Rollback Affects Transactions

Operation | Status of current record | You must also: | Status of data source
AddNew and Update, then Rollback | Content of the current record is stored temporarily to make room for new record. New record is entered into edit buffer. After Update is called, the current record is restored to the edit buffer. |  | Addition to data source made by Update is reversed.
AddNew (without Update), then Rollback | Content of the current record is stored temporarily to make room for new record. Edit buffer contains new record. | Call AddNew again to restore the edit buffer to an empty, new record. Or call Move(0) to restore the old values to the edit buffer. | Because Update was not called, there were no changes made to the data source.
Edit and Update, then Rollback | An unedited version of the current record is stored temporarily. Edits are made to the content of the edit buffer. After Update is called, the unedited version of the record is still temporarily stored. | Dynaset: Scroll off the current record then back to restore the unedited version of the record to the edit buffer. Snapshot: Call Requery to refresh the recordset from the data source. | Changes to data source made by Update are reversed.
Edit (without Update), then Rollback | An unedited version of the current record is stored temporarily. Edits are made to the content of the edit buffer. | Call Edit again to restore the unedited version of the record to the edit buffer. | Because Update was not called, there were no changes made to the data source.
Delete then Rollback | Content of the current record is deleted. | Call Requery to restore the content of the current record from the data source. | Deletion of data from data source is reversed.

See Also Transaction (ODBC), Transaction: Performing a Transaction in a Recordset (ODBC), CDatabase, CRecordset


Date and Time Topics

Home | Overview | How Do I

This article family describes how to use MFC for working with dates and times.

Tip For information about working with date and time data in alternative ways (C run-time library, Win32 API) see the overview.

What do you want to know more about?

  • Working with the MFC date and time classes

  • Using the system clock in my date and time data

  • Working with date and time data in Automation

  • Working with date and time data in database applications

  • Calculating elapsed time (general-purpose classes)

  • Calculating elapsed time (Automation classes)

  • Formatting strings containing date and time data (general-purpose classes)

  • Formatting strings containing date and time data (Automation classes)

  • Classes CTime and CTimeSpan

  • The SYSTEMTIME and FILETIME data types

  • The DATE type

  • Classes COleDateTime and COleDateTimeSpan


Date and Time

Home | Overview | How Do I

MFC supports several different ways of working with dates and times. These include:

  • General-purpose time classes. The CTime and CTimeSpan classes encapsulate most of the functionality associated with the ANSI-standard time library, which is declared in TIME.H.

  • Support for system clock. With MFC version 3.0, support was added to CTime for the Win32 SYSTEMTIME and FILETIME data types.

  • Support for the Automation DATE data type. DATE supports date, time, and date/time values. The COleDateTime and COleDateTimeSpan classes encapsulate this functionality. They work with the COleVariant class using Automation support.

For more information, see one or more of the following articles:

  • Date and Time: General-Purpose Classes

  • Date and Time: SYSTEMTIME Support

  • Date and Time: Automation Support


Date and Time: General-Purpose Classes

Home | Overview | How Do I

This article describes how to take advantage of the class library general-purpose services related to date and time management. Procedures described include:

  • Getting the current time

  • Calculating elapsed time

  • Formatting a string representation of a date/time

The CTime class provides a way to represent date and time information easily. The CTimeSpan class represents elapsed time, such as the difference between two CTime objects.

Note CTime objects can be used to represent dates between January 1, 1970, and January 18, 2038. CTime objects have a resolution of 1 second. CTime is based on the time_t data type, defined in the Run-Time Library Reference.


Current Time: General Purpose Classes

Home | Overview | How Do I

The following procedure shows how to create a CTime object and initialize it with the current time.

To get the current time

  1. Allocate a CTime object, as follows:
    CTime theTime;

    Note Uninitialized CTime objects are not initialized to a valid time.

  2. Call the CTime::GetCurrentTime function to get the current time from the operating system. This function returns a CTime object that can be used to set the value of CTime, as follows:
    theTime = CTime::GetCurrentTime();

    Since GetCurrentTime is a static member function from the CTime class, you must qualify its name with the name of the class and the scope resolution operator (::), CTime::GetCurrentTime().

Of course, the two steps outlined previously could be combined into a single program statement as follows:

CTime theTime = CTime::GetCurrentTime();


Elapsed Time: General-Purpose Classes

Home | Overview | How Do I

The following procedure shows how to calculate the difference between two CTime objects and get a CTimeSpan result.

To calculate elapsed time

  • Use the CTime and CTimeSpan objects to calculate the elapsed time, as follows:
    CTime startTime = CTime::GetCurrentTime();

// ... perform time-consuming task ...

CTime endTime = CTime::GetCurrentTime();

CTimeSpan elapsedTime = endTime - startTime;

    Once you have calculated elapsedTime, you can use the member functions of CTimeSpan to extract the components of the elapsed-time value.


Formatting Time Values: General-Purpose Classes

Home | Overview | How Do I

The following procedure shows how to format time values.

To format a string representation of a time or elapsed time

  • Use the Format member function from either the CTime or CTimeSpan classes to create a character string representation of the time or elapsed time, as shown by the following example.
    CTime t( 1991, 3, 19, 22, 15, 0 );
// 10:15PM March 19, 1991

CString s = t.Format( "%A, %B %d, %Y" );
// s == "Tuesday, March 19, 1991"

What do you want to know more about?

  • General date and time programming in MFC

  • Working with SYSTEMTIME

  • Automation support of date and time programming


Date and Time: SYSTEMTIME Support

Home | Overview | How Do I

The CTime class has constructors that accept system and file times from Win32. If you use CTime objects for these purposes, you must modify their initialization accordingly, as described in this article.

MFC still provides CTime constructors that take time arguments of the MS-DOS style, but, with MFC version 3.0, the CTime class also supports a constructor that takes a Win32 SYSTEMTIME structure and another that takes a Win32 FILETIME structure.

The new CTime constructors are:

  • CTime( const SYSTEMTIME& sysTime );

  • CTime( const FILETIME& fileTime );

The fileTime parameter is a reference to a Win32 FILETIME structure, which represents time as a 64-bit value, a more convenient format for internal storage than a SYSTEMTIME structure and the format used by Win32 to represent the time of file creation.

If your code contains a CTime object initialized with the system time, you should use the SYSTEMTIME constructor in Win32.

You most likely will not use CTime FILETIME initialization directly. If you use a CFile object to manipulate a file, CFile::GetStatus retrieves the file timestamp for you via a CTime object initialized with a FILETIME structure.

What do you want to know more about?

  • General date and time programming in MFC

  • Automation support of date and time programming

  • General-purpose classes for date and time programming


Date and Time: Automation Support

Home | Overview | How Do I

This article describes how to take advantage of the class library services related to date and time management. Procedures described include:

  • Getting the current time

  • Calculating elapsed time

  • Formatting a string representation of a date/time

The COleDateTime class provides a way to represent date and time information. It provides finer granularity and a greater range than the CTime class. The COleDateTimeSpan class represents elapsed time, such as the difference between two COleDateTime objects.

The COleDateTime and COleDateTimeSpan classes are designed to be used with the COleVariant class used in Automation. COleDateTime and COleDateTimeSpan are also useful in MFC database programming, but they can be used whenever you want to manipulate date and time values. Although the COleDateTime class has a greater range of values and finer granularity than the CTime class, it requires more storage per object than CTime. There are also some special considerations when working with the underlying DATE type. See The DATE Type for more details on the implementation of DATE.

COleDateTime objects can be used to represent dates between January 1, 100, and December 31, 9999. COleDateTime objects are floating point values, with an approximate resolution of 1 millisecond. COleDateTime is based on the DATE data type, defined in the MFC documentation under COleDateTime::operator DATE. The actual implementation of DATE extends beyond these bounds. The COleDateTime implementation imposes these bounds to facilitate working with the class.

COleDateTime ignores Daylight Saving Time (DST). The following code example compares two methods of calculating a time span that crosses the DST switchover date: one using the CRT, and the other using COleDateTime. DST switches over, in most locales, in the second week in April and the third in October.

The first method sets two CTime objects, time1 and time2, to April 5 and April 6 respectively, using the standard C type structures tm and time_t. The code displays time1 and time2 and the time span between them.

The second method creates two COleDateTime objects, oletime1 and oletime2, and sets them to the same dates as time1 and time2. It displays oletime1 and oletime2 and the time span between them.

The CRT correctly calculates a difference of 23 hours. COleDateTimeSpan calculates a difference of 24 hours.

Note that a workaround is used near the end of the example to display the date properly using COleDateTime::Format. See the Knowledge Base article "BUG: Format("%D") Fails for COleDateTime and COleDateTimeSpan" (Q167338).

#include <afxdisp.h>

void CTimetestView::OnDraw(CDC* pDC)
{
   CTimetestDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);

   time_t date1_t, date2_t;
   tm date_tm;

   date_tm.tm_hour   =12;
   date_tm.tm_min   =0;
   date_tm.tm_mon   =3;
   date_tm.tm_sec   =0;
   date_tm.tm_wday   =0; //Day of week (0-6; Sunday = 0)
   date_tm.tm_yday =0;
   date_tm.tm_year   =97;
   date_tm.tm_isdst =-1; //Positive if Daylight Saving Time is in effect;
                         //0 if Daylight Saving Time is not in effect;
                         //Negative if status of DST is unknown.

   date_tm.tm_mday   =6;
   date2_t = mktime(&date_tm);

   date_tm.tm_mday   =5;
   date_tm.tm_isdst =0;
   date1_t = mktime(&date_tm);

   CTime time1(date1_t), time2(date2_t);
   CTimeSpan ts = time2 - time1;

   pDC->TextOut(0,0, CString("CTime"));
   pDC->TextOut(0,20, time1.Format("%H:%M:%S %A, %B %d, %Y"));
   pDC->TextOut(0,40, time2.Format("%H:%M:%S %A, %B %d, %Y"));
   pDC->TextOut(0,60, ts.Format("%H:%M:%S and %D days"));

   COleDateTime oletime1(date1_t), oletime2(date2_t);
   COleDateTimeSpan olets = oletime2 - oletime1;

   pDC->TextOut(0,120, CString("COleDateTime"));
   pDC->TextOut(0,140, oletime1.Format("%H:%M:%S %A, %B %d, %Y"));
   pDC->TextOut(0,160, oletime2.Format("%H:%M:%S %A, %B %d, %Y"));

   //Work-around bug in COleDateTime::Format("%D")
   CString str;
    str.Format("%s and %d days",
      (LPCTSTR)olets.Format("%H:%M:%S"), olets.GetDays());
   pDC->TextOut(0,180, str);


The DATE Type

Home | Overview | How Do I

The DATE type is implemented using an 8-byte floating-point number. Days are represented by whole number increments starting with 30 December 1899, midnight as time zero. Hour values are expressed as the absolute value of the fractional part of the number. The following table illustrates this.

Date and time | Representation
30 December 1899, midnight | 0.00
1 January 1900, midnight | 2.00
4 January 1900, midnight | 5.00
4 January 1900, 6 A.M. | 5.25
4 January 1900, noon | 5.50
4 January 1900, 9 P.M. | 5.875

So, the DATE date type, and also the COleDateTime class, represent dates and times as a classic number line.

However, there are discontinuities for dates before 30 December 1899. See the following table for an illustration.

Date and time | Representation
30 December 1899, midnight | 0.00
29 December 1899, midnight | -1.00
18 December 1899, midnight | -12.00
18 December 1899, 6 A.M. | -12.25
18 December 1899, noon | -12.50
18 December 1899, 6 P.M. | -12.75
19 December 1899, midnight | -11.00


Current Time: Automation Classes

Home | Overview | How Do I

The following procedure shows how to create a COleDateTime object and initialize it with the current time.

To get the current time

  1. Create a COleDateTime object.

  2. Call GetCurrentTime.
    COleDateTime timeNow;
timeNow = COleDateTime::GetCurrentTime();


Elapsed Time: Automation Classes

Home | Overview | How Do I

This procedure shows how to calculate the difference between two CTime objects and get a CTimeSpan result.

To calculate elapsed time

  1. Create two COleDateTime objects.

  2. Set one of the COleDateTime objects to the current time.

  3. Perform some time-consuming task.

  4. Set the other COleDateTime object to the current time.

  5. Take the difference between the two times.
    COleDateTime timeStart, timeEnd;
timeStart = COleDateTime::GetCurrentTime();
// ... perform time-consuming task
timeEnd = COleDateTime::GetCurrentTime();
COleDateTimeSpan spanElapsed = timeEnd - timeStart;


Formatting Time: Automation Classes

Home | Overview | How Do I

To format a time

  • Use the Format member function of either COleDateTime or COleDateTimeSpan to create a character string representing the time or elapsed time.
    COleDateTime time(70, 12, 18, 17, 30, 0);
// 18 December 1970, 5:30 PM
CString s = time.Format(VAR_DATEVALUEONLY);
// s contains the date formatted based on
// the current national language specifications
// (locale ID). The time portion is ignored for
// formatting purposes in this case.

For related information, see class COleVariant.

What do you want to know more about?

  • General date and time programming in MFC

  • General-purpose classes for date and time programming

  • Working with SYSTEMTIME


Date and Time: Database Support

Home | Overview | How Do I

As of version 4.0, MFC database programming uses the COleDateTime and COleDateTimeSpan classes to represent date and time data. These classes, also used in Automation, are derived from class COleVariant. They supply better support for managing date and time data than do CTime and CTimeSpan.

What do you want to know more about?

  • Automation support of date and time programming


DLL Topics

Home | Overview | How Do I | FAQ | Sample

Using dynamic linking instead of static linking offers several advantages. DLLs save memory, reduce swapping, save disk space, upgrade easier, provide after-market support, provide a mechanism to extend the MFC library classes, support multi-language programs, and ease the creation of international versions.

This article family provides detailed information on programming DLLs.

What do you want to know more about?

  • The differences between Win16 and Win32 DLLs

  • Run-time library behavior

  • Using implicit linking

  • LoadLibrary and AfxLoadLibrary

  • GetProcAddress

  • Linker Support for the Delayed Loading of DLLs

  • FreeLibrary and AfxFreeLibrary

  • The search path used by Windows to locate a DLL

  • Regular DLLs statically linked to MFC

  • Regular DLLs dynamically linked to MFC

  • Module States of a regular DLL dynamically linked to MFC

  • Extension DLLs

  • Using extension DLL,Database/OLE/Sockets in regular DLL

  • Using __declspec(dllimport) and __declspec(dllexport)

  • Importing and exporting inline functions

  • Mutual imports

  • Active Technology and DLLs

  • Automation in a DLL

  • Naming conventions for MFC DLLs

  • Redistributable files
    • Categories of redistributable files

    • Version checking of redistributable files

    • MFC/other DLL files

    • ODBC files
  • Calling DLL functions from Visual Basic applications

  • Using MFC as Part of a DLL

  • DLL Version of MFC


Differences Between Win16 and Win32 DLLs

Home | Overview | How Do I | FAQ | Details | Sample

If you have built 16-bit DLLs for Windows 3.x, you should find that building 32-bit DLLs for Windows 95 and Windows NT is more convenient. The compiler offers more direct support, which can save you several steps in DLL creation. The specific differences between Win16 and Win32 DLLs are:

  • There is no separate startup module that you have to link with. The DLL startup sequence is handled directly by C/C++ run-time library code linked into your DLL.

  • The run-time library code initializes any static non-local C++ objects by calling the appropriate constructors. Each process gets its own copy of all the DLL's static data, including objects.

  • You no longer need the function called LibMain or a WEP (Windows Exit Procedure). Where you add initialization and termination code for your DLL depends on the kind of DLL you are building. Instead of LibMain, you provide DllMain which is called for both for both entry and exit.

  • You can import and export symbols directly in your source code. If you use the __declspec(dllexport) attribute (similar to __export in Windows 3.x), you do not need to use a separate module-definition file for exports.

  • Executables that use __declspec(dllimport) to import data, objects, and functions from a DLL cause the compiler to generate more efficient code.

  • The timing of calls to routines registered with atexit can differ.

  • In addition to Win32 non-MFC DLLs, Visual C++ offers three kinds of MFC DLLs.

What do you want to do?

  • Export from a DLL

  • Initialize a DLL

  • Link an executable to a DLL

What do you want to know more about?

  • The different kinds of DLLs available with Visual C++

  • Using __declspec(dllimport) and __declspec(dllexport)

  • Run-time library behavior


Run-Time Library Behavior

Home | Overview | How Do I | FAQ | Details | Sample

The C/C++ run-time library code performs the DLL startup sequence, eliminating the need to link with a separate module as was necessary in Windows 3.x. Included in the C/C++ run-time library code is the DLL entry-point function called _DllMainCRTStartup. The _DllMainCRTStartup function does several things, including calling CRT_INIT, which initializes the C/C++ run-time library and invokes C++ constructors on static, non-local variables. Without this function, the run-time library would be left in an uninitialized state.

While it is possible to specify another entry-point function using the /ENTRY: linker switch, it is not recommended because your entry-point function would have to duplicate everything that _DllMainCRTStartup does. When building DLLs in Visual C++, _DllMainCRTStartup is linked in automatically and you do not need to specify an entry-point function using the /ENTRY: linker switch .

In addition to initializing the C run-time library, _DllMainCRTStartup calls a function called DllMain. Depending on the kind of DLL you are building, Visual C++ provides DllMain for you and it gets linked in so that _DllMainCRTStartup always has something to call. In this way, if you do not need to initialize your DLL, there's nothing special you have to do when building your DLL. If you need to initialize your DLL, where you add your code depends on the kind of DLL you are writing. See Initialize a DLL for more information.

The C/C++ run-time library code calls constructors and destructors on static, non-local variables. For example, in the following DLL source code, Equus and Sugar are two static, non-local objects of class CHorse, defined in HORSES.H. There is no function in source code that contains calls to a constructor function for CHorse or to the destructor function because these objects are defined outside of any function. Therefore, calls to these constructors and destructors must be performed by the run-time code. (The run-time library code for applications also performs this function.)

#include "horses.h"

CHorse  Equus( ARABIAN, MALE );
CHorse  Sugar( THOROUGHBRED, FEMALE );

BOOL    WINAPI   DllMain (HANDLE hInst,
                            ULONG ul_reason_for_call,
                            LPVOID lpReserved)
.
.
.

Each time a new process attempts to use the DLL, the operating system creates a separate copy of the DLL's data: this is called "process attach". The run-time library code for the DLL calls the constructors for all the global objects, if any, and then calls the DllMain function with process attach selected. The opposite situation is process detach: the run-time library code calls DllMain with process detach selected and then calls a list of termination functions including atexit functions, destructors for the global objects, and destructors for the static objects. Note that the order of events in process attach is the reverse of that in process detach.

The run-time library code is also called during thread attach and thread detach, but the run-time code does no initialization or termination on its own.

What do you want to do?

  • Initialize a DLL


Using Implicit Linking

Home | Overview | How Do I | FAQ | Details | Sample

Implicit linking occurs when an application's code calls an exported DLL function. When the source code for the calling executable is compiled or assembled, the DLL function call generates an external function reference in the object code. To resolve this external reference, the application must link with the import library (.LIB file) provided by the maker of the DLL.

The import library only contains code to load the DLL and to implement calls to functions in the DLL. Finding an external function in an import library informs the linker that the code for that function is in a DLL. To resolve external references to DLLs, the linker simply adds information to the executable file that tells the system where to find the DLL code when the process starts up.

When the system starts a program that contains dynamically linked references, it uses the information in the program's executable file to locate the required DLLs. If it cannot locate the DLL, the system terminates the process and displays a dialog box that reports the error. Otherwise, the system maps the DLL modules into the process's address space.

If any of the DLLs has an entry-point function (for initialization and termination code), the operating system calls the function. One of the parameters passed to the entry-point function specifies a code that indicates the DLL is attaching to the process. If the entry-point function does not return TRUE, the system terminates the process and reports the error.

Finally, the system modifies the executable code of the process to provide starting addresses for the DLL functions.

Like the rest of a program's code, DLL code is mapped into the address space of the process when the process starts up and it is loaded into memory only when needed. As a result, the PRELOAD and LOADONCALL code attributes used by .DEF files to control loading in previous versions of Windows no longer have meaning.


LoadLibrary and AfxLoadLibrary

Home | Overview | How Do I | FAQ | Details | Sample

Processes call LoadLibrary (or AfxLoadLibrary) to explicitly link to a DLL. If successful, the function maps the specified DLL into the address space of the calling process and returns a handle to the DLL that can be used with other functions used in explicit linking such as GetProcAddresss and FreeLibrary.

LoadLibrary attempts to locate the DLL using the same search sequence used for implicit linking. If the system cannot find the DLL or if the entry-point function returns FALSE, LoadLibrary returns NULL. If the call to LoadLibrary specifies a DLL module already mapped into the address space of the calling process, the function simply returns a handle of the DLL and increments the module's reference count.

If the DLL has an entry-point function, the operating system calls the function in the context of the thread that called LoadLibrary. The entry-point function is not called if the DLL is already attached to the process because of a previous call to LoadLibrary with no corresponding call to the FreeLibrary function.

MFC applications loading extension DLLs should use AfxLoadLibrary instead of LoadLibrary. AfxLoadLibrary handles thread synchronization before calling LoadLibrary. The interface (function prototype) to AfxLoadLibrary is the same as LoadLibrary.

If for some reason Windows cannot load the DLL, the process can attempt to recover from the error. For example, the process could notify the user of the error and have the user specify another path to the DLL.

What do you want to do?

  • Link implicitly

  • Determine which linking method to use

What do you want to know more about?

  • GetProcAddress

  • FreeLibrary

  • The search path used by Windows to locate a DLL


GetProcAddress

Home | Overview | How Do I | FAQ | Details | Sample

Processes explicitly linking to a DLL call GetProcAddress to obtain the address of an exported function in the DLL. You use the returned function pointer to call the DLL function. GetProcAddress takes as parameters the DLL module handle (returned by either LoadLibrary, AfxLoadLibrary, or GetModuleHandle), and either the name of the function you want to call or the function's export ordinal.

Because you are calling the DLL function through a pointer and there is no compile-time type checking, make sure that the parameters to the function are correct so that you do not over step the memory allocated on the stack and cause an access violation. One way to ensure type safety is to look at the function prototypes of the exported functions and create matching typedefs for the function pointers. For example:

typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);
.
.
.
HINSTANCE hDLL;               // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1;    // Function pointer
DWORD dwParam1;
UINT  uParam2, uReturnVal;

hDLL = LoadLibrary("MyDLL");
if (hDLL != NULL)
{
   lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,
                                           "DLLFunc1");
   if (!lpfnDllFunc1)
   {
      // handle the error
      FreeLibrary(hDLL);
      return SOME_ERROR_CODE;
   }
   else
   {
      // call the function
      uReturnVal = lpfnDllFunc1(dwParam1, uParam2);
   }
}

How you specify the function you want when calling GetProcAddress depends on how the DLL was built.

You can only obtain the export ordinal if the DLL you are linking to was built with a module definition (.DEF) file, and if the ordinals are listed with the functions in the EXPORTS section of the DLL's .DEF file. Calling GetProcAddress with an export ordinal, as opposed to the function name, is slightly faster if the DLL has many exported functions because the export ordinals serve as indexes into the DLL's export table. With an export ordinal, GetProcAddress can locate the function directly as opposed to comparing the specified name to the function names in the DLL's export table. However, you should call GetProcAddress with an export ordinal only if you have control over assigning the ordinals to the exported functions in the .DEF file.

What do you want to do?

  • Link implicitly

  • Determine which linking method to use

What do you want to know more about?

  • LoadLibrary and AfxLoadLibrary

  • FreeLibrary


Linker Support for Delay-Loaded DLLs

The Visual C++ linker now supports the delayed loading of DLLs. This relieves you of the need to use the Win32 SDK functions LoadLibrary and GetProcAddress to implement DLL delayed loading.

You should consider delay loading a DLL if:

  • Your program may not call a function in the DLL.

  • A function in the DLL may not get called until late in your program's execution.

The following topics describe delay loading DLLs:

  • Specifying DLLs to Delay Load

  • Explicitly Unloading a Delay-Loaded DLL

  • Binding Imports

  • Error Handling and Notification

  • Dumping Delay-Loaded Imports

  • Constraints of Delay Loading DLLs

  • Understanding the Helper Function

  • Developing Your Own Helper Function


Specifying DLLs to Delay Load

You can specify which DLLs to delay load with the /delayload :dllname linker switch. If you do not plan to use your own version of a helper function, you must also link your program with Delayimp.lib.


Explicitly Unloading a Delay-Loaded DLL

By default, when your code unloads the DLL (with __FUnloadDelayLoadedDLL), the delay-loaded imports remain in the IAT table. However, if you use the /delay :unload switch on the linker command line, the helper function will support the explicit unloading of the DLL, resetting the IAT to its original form; the now-invalid pointers will be overwritten.

See Unloading a Delay-Loaded DLL for more information.


Binding Imports

The default linker behavior is to create a bindable IAT for the delay-loaded DLL. If the DLL is bound, the helper function will attempt to use the bound information instead of calling GetProcAddress on each of the referenced imports. If either the timestamp or the preferred address do not match those of the loaded DLL, the helper function will assume the bound IAT is out of date and will proceed as if the bound IAT does not exist.

If you never intend to bind the DLL, specifying /delay :nobind on the linker's command line will prevent the bound IAT from being emitted.


Error Handling and Notification

For more information on error handling and notification, see Understanding the Helper Function.

If your program uses delay-loaded DLLs, it must handle errors robustly since failures will occur while the program is running, before any user code gets executed. Failure handling is comprised of two portions:

Recovery through a hook.

If your code needs to recover or provide an alternate library and/or routine on failure, a hook can be provided to the helper function that can supply or remedy the situation. The hook routine needs to return a suitable value, so that processing can continue (an HINSTANCE or FARPROC) or 0 to indicate that an exception should be thrown. It could also throw its own exception or longjmp out of the hook. There are notification hooks and failure hooks.

Reporting via an exception.

If all that is necessary for handling the error is to abort the procedure, no hook is necessary as long as the user code can handle the exception.

The following sections discuss error handling and notification:

  • Notification Hooks

  • Failure Hooks

  • Exceptions


Notification Hooks

The notification hook is enabled:

  • By supplying a new definition of the pointer __pfnDliNotifyHook that is initialized to point to your own function that receives the notifications, or

  • By setting the pointer __pfnDliNotifyHook to the function before any calls to the DLL that the program is delay loading.

If this pointer is initialized (non-zero), the delay load helper will invoke the function at certain notification points throughout its execution. The function pointer has the following definition:

// The "notify hook" gets called for every call to the
// delay load helper. This allows a user to hook every call and
// skip the delay load helper entirely.
//
// dliNotify == {
//  dliStartProcessing |
//  dliPreLoadLibrary  |
//  dliPreGetProc |
//  dliNoteEndProcessing}
//  on this call.
//
#if defined(__cplusplus)
extern "C"
#endif
extern
PfnDliHook   __pfnDliNotifyHook;

The notifications pass in a DelayLoadInfo structure to the hook function along with the notification value. This data is identical to that used by the delay load helper routine. The notification value will be one of the values defined in Structure and Constant Definitions.


Failure Hooks

The failure hook is enabled in the same manner as the notification hook. The pointer variable that refers to the user-defined function is:

// This is the failure hook, dliNotify = {dliFailLoadLib|dliFailGetProc}
#if defined(__cplusplus)
extern "C"
#endif
extern
PfnDliHook   __pfnDliFailureHook;

The DelayLoadInfo structure contains all the pertinent data necessary for accurate reporting of the error, including the value from GetLastError.


Exceptions

There are two exception codes that can be raised when failures are encountered:

  • For a LoadLibrary failure, and

  • For a GetProcAddress failure.

Here is the exception information:

//
// Exception information
//
#define FACILITY_VISUALCPP  ((LONG)0x6d)
#define VcppException(sev,err)  ((sev) | (FACILITY_VISUALCPP<<16) | err)

The exception codes thrown are the standard VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND) and VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND) values. The exception passes a pointer to a DelayLoadInfo structure in the LPDWORD value that can be retrieved by GetExceptionInformation in the EXCEPTION_RECORD structure, ExceptionInformation[0] field. See to Structure and Constant Definitions for more information.


Dumping Delay-Loaded Imports

Delay-loaded imports can be dumped using the linker (link /dump /imports or dumpbin /imports) and show up with slightly different information than standard imports. They are segregated into their own section of the /imports dumping and are explicitly labeled as delay-loaded imports. If there is unload information present in the image, that is noted. If there is bind information present, the time/date stamp of the target DLL is noted along with the bound addresses of the imports.


Constraints of Delay Loading DLLs

There are constraints regarding the delay loading of imports.

  • Imports of data cannot be supported. A workaround is to explicitly handle the data import yourself using LoadLibrary (or GetModuleHandle after you know the delay-load helper has loaded the DLL) and GetProcAddress.

  • Delay loading Kernel32.dll not supported. This DLL is necessary for the delay-load helper routines to perform the delay loading.

  • Binding of entry points that are forwarded is not supported.

  • Delay loading of a DLL may not result in the same behavior of the process if there are per-process initializations that occur in the entry point of the delay-loaded DLL. Other cases include static TLS (thread local storage, declared using __declspec(thread) which is not handled when the DLL is loaded via LoadLibrary. Dynamic TLS, using TlsAlloc, TlsFree, TlsGetValue, TlsSetValue is still available for use in either static or delay-loaded DLLs.

  • Static (global) function pointers should be reinitialized to imported functions after the first call to the function. This is because the first use of the function pointer will point to the thunk.


Understanding the Helper Function

The helper function for linker-supported delayed loading is what actually loads the DLL at run time. You can modify the helper function to customize its behavior by writing your own function and linking it to your program instead of using the supplied helper function in Delayimp.lib. One helper function serves all delay loaded DLLs.

The helper function performs the following actions:

  • Checks the stored handle to the library to see if it has already been loaded

  • Calls LoadLibrary to attempt loading of the DLL

  • Calls GetProcAddress to attempt getting the address of the procedure

  • Returns to the delay import load thunk to call the now-loaded entry point

The helper function can call back to a notification hook in your program after each of the following actions:

  • When the helper function starts up

  • Just before LoadLibrary is called in the helper function

  • Just before GetProcAddress is called in the helper function

  • If the call to LoadLibrary in the helper function failed

  • If the call to GetProcAddress in the helper function failed

  • After the helper function is done processing

Each of these hook points can return a value that will alter normal processing of the helper routine in some manner except the return to the delay import load thunk.

The default helper code can be found in Delayhlp.cpp and Delayimp.h (in vc\include) and is compiled in Delayimp.lib (in vc\lib). You will need to include this library in your compilations unless you write your own helper function.

The following topics describe the helper function:

  • Calling Conventions and Parameters

  • Structure and Constant Definitions

  • Calculating Necessary Values

  • Return Value

  • Explicitly Unloading a Delay-Loaded DLL


Calling Conventions and Parameters

The helper routine's prototype is:

#if defined(__cplusplus)
extern "C"
#endif
FARPROC WINAPI
__delayLoadHelper(
    PCImgDelayDescr pidd,
    FARPROC *       ppfnIATEntry
    );

The calling convention is __stdcall and it returns a function pointer. The type of the return value is not relevant, so FARPROC is used. Also note that this function has C linkage. The parameters are a pointer to a const ImgDelayDescr and a pointer to the particular IAT entry to update. The helper routine needs to store the same value that it will be returning into this location.


Structure and Constant Definitions

There are several different structures that the default helper routine uses to communicate with the hook functions and during any exceptions. Here are the notification and failure values, information structures, and the pointer-to-hook-function type passed to the hooks:

//
// Delay load import hook notifications
//
enum {
    dliStartProcessing,             // used to bypass or note helper only
    dliNotePreLoadLibrary,          // called just before LoadLibrary, can
                                    //  override w/ new HMODULE return val
    dliNotePreGetProcAddress,       // called just before GetProcAddress, can
                                    //  override w/ new FARPROC return value
    dliFailLoadLib,                 // failed to load library, fix it by
                                    //  returning a valid HMODULE
    dliFailGetProc,                 // failed to get proc address, fix it by
                                    //  returning a valid FARPROC
    dliNoteEndProcessing,           // called after all processing is done, no
                                    //  no bypass possible at this point except
                                    //  by longjmp()/throw()/RaiseException.
    };

typedef struct DelayLoadProc {
    BOOL                fImportByName;
    union {
        LPCSTR          szProcName;
        DWORD           dwOrdinal;
        };
    } DelayLoadProc;

typedef struct DelayLoadInfo {
    DWORD               cb;         // size of structure
    PCImgDelayDescr     pidd;       // raw form of data (everything is there)
    FARPROC *           ppfn;       // points to address of function to load
    LPCSTR              szDll;      // name of dll
    DelayLoadProc       dlp;        // name or ordinal of procedure
    HMODULE             hmodCur;    // the hInstance of the library we have loaded
    FARPROC             pfnCur;     // the actual function that will be called
    DWORD               dwLastError;// error received (if an error notification)
    } DelayLoadInfo, * PDelayLoadInfo;

typedef FARPROC (WINAPI *PfnDliHook)(
    unsigned        dliNotify,
    PDelayLoadInfo  pdli
    );


Calculating Necessary Values

There are two critical pieces of information that need to be calculated by the delay helper routine. To that end, there are a couple of inline functions in the header file, Delayimp.h, for calculating this information. The first one is for calculating the index of the current import into the three different tables (IAT, BIAT, and UIAT) and the second for counting the number of imports in a valid IAT:

// utility function for calculating the index of the current import
// for all the tables (INT, BIAT, UIAT, and IAT).
__inline unsigned
IndexFromPImgThunkData(PCImgThunkData pitdCur, PCImgThunkData pitdBase) {
    return pitdCur - pitdBase;
    }

// utility function for calculating the count of imports given the base
// of the IAT. NB: this only works on a valid IAT!
__inline unsigned
CountOfImports(PCImgThunkData pitdBase) {
    unsigned        cRet = 0;
    PCImgThunkData  pitd = pitdBase;
    while (pitd->u1.Function) {
        pitd++;
        cRet++;
        }
    return cRet;
    }


Return Value

The return value of the delay load helper needs to be stored in the passed-in-function pointer location, unless you want your helper routine to be used as a notification hook. In that case, your code is responsible for finding the appropriate function pointer to return. The thunk code the linker generates then takes that return value as the real target of the import and jumps directly to it.


Unloading a Delay-Loaded DLL

The default-supplied delay-load helper checks to see if the delay-load descriptors have a pointer and a copy of the original IAT in the pUnloadIAT field. If so, it will save a pointer in a list to the import delay descriptor. This enables the helper function to find the DLL by name to support unloading that DLL explicitly.

Here are the associated structures and functions for explicitly unloading a delay-loaded DLL:

//
// Unload support
//

// routine definition; takes a pointer to a name to unload, or NULL to
// unload all the delay load dlls in the list.
//
#if defined(__cplusplus)
extern "C"
#endif
BOOL WINAPI
__FUnloadDelayLoadedDLL(LPCSTR szDll);

// structure definitions for the list of unload records
typedef struct UnloadInfo * PUnloadInfo;
typedef struct UnloadInfo {
    PUnloadInfo     puiNext;
    PCImgDelayDescr pidd;
    } UnloadInfo;

// the default delay load helper places the unloadinfo records in the list
// headed by the following pointer.
#if defined(__cplusplus)
extern "C"
#endif
extern
PUnloadInfo __puiHead;

The UnloadInfo structure is implemented using a C++ class that uses LocalAlloc and LocalFree implementations as its operator new and operator delete respectively. These options are kept in a standard linked list using __puiHead as the head of the list.

Calling the supplied unload routine will attempt to find the name you provide in the list of loaded DLLs (an exact match is required). If found, the copy of the IAT in pUnloadIAT is copied over the top of the running IAT to restore the thunk pointers, the library is freed with FreeLibrary, the matching UnloadInfo record is unlinked from the list and deleted, and TRUE is returned.


Developing Your Own Helper Function

You may wish to provide your own version of the routine to do specific processing based on the names of the DLL or imports. There are two methods of doing this: coding your own, possibly based on the supplied code, or merely hooking the supplied version using the notification hooks detailed previously.

Code Your Own

This is fairly simple since you can essentially use the supplied code as a guideline for the new one. Of course, it must adhere to the calling conventions and if it returns to the linker-generated thunks, it must return a proper function pointer. Once in your code, you can do pretty much whatever you want in order to satisfy the call or get out of the call.

Use the Start Processing Notification Hook

It will probably be easiest to simply provide a new pointer to a user-supplied notification hook function that receives the same values as the default helper on the notification dliStartProcessing. At that point, the hook function can essentially become the new helper function, as a successful return to the default helper will bypass all further processing in the default helper.


FreeLibrary and AfxFreeLibrary

Home | Overview | How Do I | FAQ | Details | Sample

Processes explicitly linking to a DLL call the FreeLibrary function when the DLL module is no longer needed. This function decrements the module's reference count and if the reference count is zero, unmaps it from the address space of the process.

MFC applications should use AfxFreeLibrary instead of FreeLibrary to unload an extension DLL. The interface (function prototype) for AfxFreeLibrary is the same as FreeLibrary.

What do you want to do?

  • Link implicitly

  • Determine which linking method to use

What do you want to know more about?

  • LoadLibrary and AfxLoadLibrary

  • GetProcAddress


The Search Path Used by Windows to Locate a DLL

Home | Overview | How Do I | FAQ | Details | Sample

With both implicit and explicit linking, Windows first searches the set of pre-installed DLLs such as the performance library (KERNEL32.DLL) and the security library (USER32.DLL). Windows then searches for the DLLs in the following sequence:

  1. The directory where the executable module for the current process is located.

  2. The current directory.

  3. The Windows system directory. The GetSystemDirectory function retrieves the path of this directory.

  4. The Windows directory. The GetWindowsDirectory function retrieves the path of this directory.

  5. The directories listed in the PATH environment variable.

    Note that the LIBPATH environment variable is not used.

What do you want to do?

  • Link implicitly

  • Link explicitly

  • Determine which linking method to use


Regular DLLs Statically Linked to MFC

Home | Overview | How Do I | FAQ | Details | Sample

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

A regular DLL, statically linked to MFC is a DLL that uses MFC internally, and the exported functions in the DLL can be called by either MFC or non-MFC executables.

A regular DLL, statically linked to MFC has the following features:

  • The client executable can be written in any language that supports the use of DLLs (C, C++, Pascal, Visual Basic, etc.); it does not have to be an MFC application.

  • The DLL can link to the same MFC static link libraries used by applications. There is no longer a separate version of the static link libraries for DLLs.

  • Before version 4.0 of MFC, USRDLLs provided the same type of functionality as regular DLLs statically linked to MFC. As of Visual C++ version 4.0, the term "USRDLL" is obsolete.

A regular DLL, statically linked to MFC has the following requirements:

  • This type of DLL must instantiate a class derived from CWinApp.

  • This type of DLL uses the DllMain provided by MFC. Place all DLL-specific initialization code in the InitInstance member function and termination code in ExitInstance as in a normal MFC application.

  • Even though the term "USRDLL" is obsolete, you must still define "_USRDLL" on the compiler command line. This definition determines which declarations, etc., will be pulled in from the MFC header files.

Regular DLLs must have a CWinApp-derived class and a single object of that application class, as does an MFC application. However, the CWinApp object of the DLL does not have a main message pump, as does the CWinApp object of an application.

The following MFC capabilities are not applicable in DLLs, either because of technical limitations or because those services are usually provided by the application.

  • CWinApp::Enable3dControls

  • CWinApp::SetDialogBkColor (color is ignored for message boxes)

Note that the CWinApp::Run mechanism does not apply to a DLL, since the application owns the main message pump. If the DLL opens modeless dialogs or has a main frame window of its own, the application's main message pump must call a routine exported by the DLL which in turn calls the CWinApp::PreTranslateMessage member function of the DLL's application object.

For an example of this function, see the DLLTRACE sample.

Symbols are usually exported from a regular DLL using the standard C interface. The declaration of a function exported from a regular DLL would look something like this:

extern "C" __declspec(dllexport) MyExportedFunction( );

All memory allocations within a regular DLL should stay within the DLL; the DLL should not pass to or receive from the calling executable any of the following:

  • pointers to MFC objects

  • pointers to memory allocated by MFC

If you need to do any of the above, or if you need to pass MFC-derived objects between the calling executable and the DLL, then you must build an extension DLL.

It is safe to pass pointers to memory that were allocated by the C run-time libraries between an application and a DLL only if you make a copy of the data. You must not delete or resize these pointers or use them without making a copy of the memory.

A DLL that is statically linked to MFC cannot also dynamically link to the shared MFC DLLs. A DLL that is statically linked to MFC is dynamically bound to an application just like any other DLL; applications link to it just like any other DLL.

The standard MFC static link libraries are named according to the convention described in the topic Naming conventions for MFC DLLs. However, with MFC version 3.0 and later, it is no longer necessary to manually specify to the linker the version of the MFC library you want linked in. Instead, the MFC header files automatically determine the correct version of the MFC library to link in based on preprocessor defines, such as _DEBUG or _UNICODE. The MFC header files add /DEFAULTLIB directives instructing the linker to link in a specific version of the MFC library.

What do you want to do?

  • Initialize regular DLLs

What do you want to know more about?

  • Using MFC as Part of a DLL

  • Using extension DLL,Database/OLE/Sockets in regular DLL

  • The build settings generated by AppWizard for MFC DLLs

  • Regular DLLs dynamically linked to MFC

  • Extension DLLs


Regular DLLs Dynamically Linked to MFC

Home | Overview | How Do I | FAQ | Details | Sample

A regular DLL, dynamically linked to MFC is a DLL that uses MFC internally, and the exported functions in the DLL can be called by either MFC or non-MFC executables.

A regular DLL, dynamically linked to MFC has the following features:

  • This is a new type of DLL introduced by Visual C++ 4.0.

  • The client executable can be written in any language that supports the use of DLLs (C, C++, Pascal, Visual Basic, etc.); it does not have to be an MFC application.

  • Unlike the statically-linked regular DLL, this type of DLL is dynamically linked to the MFC DLL (also known as the shared MFC DLL).

  • The MFC import library linked to this type of DLL is the same one used for extension DLLs or applications using the MFC DLL: MFCxx(D).LIB.

A regular DLL, dynamically linked to MFC has the following requirements:

  • These DLLs are compiled with _AFXDLL defined, just like an executable which is dynamically linked to the MFC DLL. But _USRDLL is also defined, just like a regular DLL which is statically linked to MFC.

  • This type of DLL must instantiate a CWinApp-derived class.

  • This type of DLL uses the DllMain provided by MFC. Place all DLL-specific initialization code in the InitInstance member function and termination code in ExitInstance as in a normal MFC application.

Because this kind of DLL uses the dynamic link library version of MFC, you must explicitly set the current module state to the one for the DLL. To do this, use the AFX_MANAGE_STATE macro at the beginning of every function exported from the DLL.

Regular DLLs must have a CWinApp-derived class and a single object of that application class, as does an MFC application. However, the CWinApp object of the DLL does not have a main message pump, as does the CWinApp object of an application.

The following MFC capabilities are not applicable in DLLs, either because of technical limitations or because those services are usually provided by the application.

  • CWinApp::Enable3dControls

  • CWinApp::SetDialogBkColor (color is ignored for message boxes)

Note that the CWinApp::Run mechanism does not apply to a DLL, since the application owns the main message pump. If your DLL brings up modeless dialogs or has a main frame window of its own, your application's main message pump must call a DLL-exported routine that calls CWinApp::PreTranslateMessage.

Place all DLL-specific initialization in the CWinApp::InitInstance member function as in a normal MFC application. The CWinApp::ExitInstance member function of your CWinApp derived class will be called from the MFC provided DllMain function before the DLL is unloaded.

You must distribute the shared DLLs MFCx0.DLL and MSVCRT.DLL (or similar files) with your application. See the topic Redistributable Files for a complete list of the MFC redistributable files.

A DLL that is dynamically linked to MFC cannot also statically link to MFC. Applications link to regular DLLs dynamically linked to MFC it just like any other DLL.

Symbols are usually exported from a regular DLL using the standard C interface. The declaration of a function exported from a regular DLL looks something like this:

extern "C" __declspec(dllexport) MyExportedFunction( );

All memory allocations within a regular DLL should stay within the DLL; the DLL should not pass to or receive from the calling executable any of the following:

  • pointers to MFC objects

  • pointers to memory allocated by MFC

If you need to do any of the above, or if you need to pass MFC-derived objects between the calling executable and the DLL, then you must build an extension DLL.

It is safe to pass pointers to memory that were allocated by the C run-time libraries between an application and a DLL only if you make a copy of the data. You must not delete or resize these pointers or use them without making a copy of the memory.

When building a regular DLL that dynamically links to MFC, you need to use the macro AFX_MANAGE_STATE to switch the MFC module state correctly. This is done by adding the following line of code to the beginning of functions exported from the DLL:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

The AFX_MANAGE_STATE macro should not be used in regular DLLs that statically link to MFC or in extension DLLs. For more information, see Managing the State Data of MFC Modules.

What do you want to do?

  • Initialize regular DLLs

What do you want to know more about?

  • The module states of a regular DLL dynamically linked to MFC

  • Managing the state data of MFC modules

  • Using extension DLL,Database/OLE/Sockets in regular DLL

  • Using MFC as Part of a DLL

  • The different kinds of DLLs available with Visual C++


Module States of a Regular DLL Dynamically Linked to MFC

Home | Overview | How Do I | FAQ | Details | Sample

The ability to dynamically link a regular DLL to the MFC DLL allows some configurations which are very complicated. For example, a regular DLL and the executable that uses it can both dynamically link to the MFC DLL and to any extension DLLs.

This configuration poses a problem with regard to MFC's global data — things like the pointer to the current CWinApp object, handle maps, etc.

Before MFC version 4.0, this global data resided in the MFC DLL itself and was shared by all the modules in the process. Since each process using a Win32 DLL gets its own copy of the DLL's data, this scheme provided an easy way to track per-process data, and since the AFXDLL model presumed that there would be only one CWinApp object and only one set of handle maps in the process, these items could be tracked in the MFC DLL itself.

But with the ability to dynamically link a regular DLL to the MFC DLL, it is now possible to have two or more CWinApp objects in a process — and also two or more sets of handle maps, etc. How does MFC keep track of which ones it should be using?

The solution is to give each module (application or regular DLL) its own copy of this global state information. Thus, a call to AfxGetApp in the regular DLL returns a pointer to the CWinApp object in the DLL, not the one in the executable. This per-module copy of MFC's global data is known as a "module state" and is described in MFC TechNote 58.

MFC's common window procedure automatically switches to the correct module state, so you don't need to worry about it in any message handlers implemented in your regular DLL. But when your executable calls into the regular DLL, you do need to explicitly set the current module state to the one for the DLL. To do this, use the AFX_MANAGE_STATE macro in every function exported from the DLL. This is done by adding the following line of code to the beginning of functions exported from the DLL:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

What do you want to know more about?

  • Managing the state data of MFC modules

  • Regular DLLs dynamically linked to MFC

  • Extension DLLs


Extension DLLs

Home | Overview | How Do I | FAQ | Details | Sample

An MFC extension DLL is a DLL that typically implements reusable classes derived from the existing Microsoft Foundation Class Library classes.

An MFC extension DLL has the following features and requirements:

  • The client EXE must be an MFC application compiled with _AFXDLL defined.

  • An extension DLL can also be used by a regular DLL which dynamically linked to MFC.

  • Extension DLLs should be compiled with _AFXEXT defined. This will force _AFXDLL to be also defined and ensures that the proper declarations, etc., will be pulled in from the MFC header files. It also ensures that AFX_EXT_CLASS will be defined as __declspec(dllexport) while building the DLL, which is necessary if you are using this macro to declare the classes in your extension DLL.

  • Extension DLLs should not instantiate a class derived from CWinApp, but should rely on the client application (or DLL) to provide this object.

  • Extension DLLs should, however, provide a DllMain function and do any necessary initialization there.

Extension DLLs are built using the dynamic link library version of MFC (also known as the shared version of MFC). Only MFC executables (either applications or regular DLLs) that are built with the shared version of MFC can use an extension DLL. Both the client application and the extension DLL must use the same version of MFCx0.DLL. With an extension DLL, you can derive new custom classes from MFC and then offer this "extended" version of MFC to applications that call your DLL.

Extension DLLs can also be used for passing MFC-derived objects between the application and the DLL. The member functions associated with the passed object exist in the module where the object was created. Since these functions are properly exported when using the shared DLL version of MFC, you can freely pass MFC or MFC-derived object pointers between an application and the extension DLLs it loads.

An MFC extension DLL uses a shared version of MFC in the same way an application uses the shared DLL version of MFC, with a few additional considerations:

  • It does not have a CWinApp-derived object. It must work with the CWinApp-derived object of the client application. This means that the client application owns the main message pump, the idle loop, and so on.

  • It calls AfxInitExtensionModule in its DllMain function. The return value of this function should be checked. If a zero value is returned from AfxInitExtensionModule, return 0 from your DllMain function.

  • It will create a CDynLinkLibrary object during initialization if the extension DLL wishes to export CRuntimeClass objects or resources to the application.

Before version 4.0 of MFC, this type of DLL was called an AFXDLL. AFXDLL refers to the _AFXDLL preprocessor symbol that is defined when building the DLL.

The import libraries for the shared version of MFC are named according to the convention described in the topic Naming conventions for MFC DLLs. Visual C++ supplies prebuilt versions of the MFC DLLs, plus a number of non-MFC DLLs that you can use and distribute with your applications. These are documented in REDISTRB.WRI, which is found in the \OS\System directory on the Visual C++ CD-ROM.

If you are exporting using a .DEF file, place the following code at the beginning and end of your header file:

#undef AFX_DATA
#define AFX_DATA AFX_EXT_DATA
// <body of your header file>
#undef AFX_DATA
#define AFX_DATA

These four lines ensure that your code will be compiled correctly for an extension DLL. Leaving out these four lines may cause your DLL to either compile or link incorrectly.

If you need to pass an MFC or MFC-derived object pointer to or from an MFC DLL, the DLL should be an extension DLL. The member functions associated with the passed object exist in the module where the object was created. Since these functions are properly exported when using the shared DLL version of MFC, you can freely pass MFC or MFC-derived object pointers between an application and the extension DLLs it loads.

Due to C++ name mangling and export issues, the export list from an extension DLL may be different between the debug and retail versions of the same DLL and DLLs for different platforms. The retail MFCx0.DLL has about 2,000 exported entry points; the debug MFCx0D.DLL has about 3,000 exported entry points.

Memory Management

MFCx0.DLL and all extension DLLs loaded into a client application's address space will use the same memory allocator, resource loading, and other MFC "global" states as if they were in the same application. This is significant because the non-MFC DLL libraries and the regular DLLs do the exact opposite and have each DLL allocating out of its own memory pool.

If an extension DLL allocates memory, then that memory can freely intermix with any other application-allocated object. Also, if an application that dynamically links to MFC crashes, the protection of the operating system will maintain the integrity of any other MFC application sharing the DLL.

Similarly other "global" MFC states, like the current executable file to load resources from, are also shared between the client application and all MFC extension DLLs as well as MFCx0.DLL itself.

Sharing Resources and Classes

Exporting resources is done through a resource list. Each application contains a singly linked list of CDynLinkLibrary objects. When looking for a resource, most of the standard MFC implementations that load resources look first at the current resource module (AfxGetResourceHandle) and if the resource is not found walk the list of CDynLinkLibrary objects attempting to load the requested resource.

Walking the list has the disadvantages that it is slightly slower and requires managing resource ID ranges. It has the advantage that a client application that links to several extension DLLs can use any DLL-provided resource without having to specify the DLL instance handle. AfxFindResourceHandle is an API used for walking the resource list to look for a given match. It takes the name and type of a resource and returns the resource handle where it was first found (or NULL).

If you wish to not walk the list and only load resources from a specific place, use the functions AfxGetResourceHandle and AfxSetResourceHandle to save the old handle and set the new handle. Be sure to restore the old resource handle before you return to the client application. For an example of using this approach to explicitly loading a menu, see the file TESTDLL2 .CPP in the sample DLLHUSK.

Dynamic creation of MFC objects given an MFC name is similar. The MFC object deserialization mechanism needs to have all of the CRuntimeClass objects registered so that it can reconstruct by dynamically creating C++ objects of the required type based on what was stored earlier.

In the case of the MFC Advanced Concepts sample DLLHUSK, the list looks something like:

head ->   DLLHUSK.EXE   - or -   DLLHUSK.EXE
               |                      |
          TESTDLL2.DLL           TESTDLL2.DLL
               |                      |
          TESTDLL1.DLL           TESTDLL1.DLL
               |                      |
           MFCOxxD.DLL                |
               |                      |
           MFCDxxD.DLL                |
               |                      |
            MFCxxD.DLL            MFCxx.DLL

where xx is the version number; for example, '42' represents version 4.2.

The MFCxx.DLL is usually last on the resource and class list. MFCxx.DLL includes all of the standard MFC resources, including prompt strings for all the standard command IDs. Placing it at the end of the list allows DLLs and the client application itself not to have their own copy of the standard MFC resources, but to rely on the shared resources in the MFCxx.DLL instead.

Merging the resources and class names of all DLLs into the client application's name space has the disadvantage of requiring you to be careful with what IDs or names you pick.

The DLLHUSK sample manages the shared resource name space by using multiple header files.

If your MFC extension DLL needs to maintain extra data for each application, you can derive a new class from CDynLinkLibrary and create it in DllMain. When running, the DLL can check the current application's list of CDynLinkLibrary objects to find the one for that particular extension DLL.

What do you want to do?

  • Initialize an extension DLL

What do you want to know more about?

  • Tips on using shared resource files

  • DLL Version of MFC

  • Regular DLLs statically linked to MFC

  • Regular DLLs dynamically linked to MFC

  • Using Extension DLL,Database/OLE/Sockets in Regular DLL


Using Extension DLL,Database/OLE/Sockets in Regular DLL

Home | Overview | How Do I | FAQ | Details | Sample

When using an extension DLL from a regular DLL, if the extension DLL is not wired into the CDynLinkLibrary object chain of the regular DLL, you may run into one or more of a set of related problems. Because the debug versions of the MFC Database, OLE, and Sockets support DLLs are implemented as extension DLLs, you might see similar problems if you are using these MFC features, even if you're not explicitly using any of your own extension DLLs. Some symptoms are:

  • When attempting to de-serialize an object of a type of class defined in the extension DLL, the message "Warning: Cannot load CYourClass from archive. Class not defined." appears in the TRACE debug window and the object fails to serialize.

  • An exception indicating 'bad class' may be thrown.

  • Resources stored in the extension DLL fail to load because AfxFindResourceHandle returns NULL or an incorrect resource handle.

  • DllGetClassObject, DllCanUnloadNow, and the UpdateRegistry, Revoke, RevokeAll, and RegisterAll member functions of COleObjectFactory fail to locate a class factory defined in the extension DLL.

  • AfxDoForAllClasses does not work for any classes in the extension DLL.

  • Standard MFC database, sockets, or OLE resources fail to load. For example, AfxLoadString(AFX_IDP_SQL_CONNECT_FAIL) returns an empty string, even when the regular DLL is properly using the MFC Database classes.

The solution to these problems is to create and export an initialization function in the extension DLL that creates a CDynLinkLibrary object. Call this initialization function exactly once from each regular DLL which uses the extension DLL.

MFC OLE, MFC Database (or DAO), or MFC Sockets Support

If you are using any MFC OLE, MFC Database (or DAO), or MFC Sockets support in your regular DLL, respectively, the MFC debug extension DLLs MFCOxxD.DLL, MFCDxxD.DLL, and MFCNxxD.DLL (where xx is the version number) are linked in automatically. You must call a predefined initialization function for each of these DLLs that you are using.

For database support, add a call to AfxDbInitModule to your regular DLL's CWinApp::InitInstance function. Make sure this call occurs before any base-class call or any added code which accesses the MFCDxxD.DLL. This function takes no parameters and returns void.

For OLE support, add a call to AfxOleInitModule to your regular DLL's CWinApp::InitInstance. Note that the COleControlModule InitInstance function calls AfxOleInitModule already, so if you are building an OLE control and are using COleControlModule, you should not add this call to AfxOleInitModule.

For Sockets support, add a call to AfxNetInitModule to your regular DLL's CWinApp::InitInstance.

Note that release builds of MFC DLLs and applications do not use separate DLLs for database, sockets, or OLE support. However, it is safe to call these initialization functions in release mode.

CDynLinkLibrary Objects

During each of the operations mentioned at the beginning of this article, MFC needs to search for a desired value or object. For example, during de-serialization, MFC needs to search through all of the currently available runtime classes to match objects in the archive with their proper runtime class.

As a part of these searches, MFC scans through all of the extension DLLs in use by walking a chain of CDynLinkLibrary objects. CDynLinkLibrary objects attach automatically to a chain during their constructor and are created by each extension DLL in turn during initialization. In addition, every module (application or regular DLL) has its own chain of CDynLinkLibrary objects.

In order for an extension DLL to get wired into a CDynLinkLibrary chain, it must create a CDynLinkLibrary object in the context of every module that uses the extension DLL. Therefore, if an extension DLL is going to be used from regular DLLs, it must provide an exported initialization function that creates a CDynLinkLibrary object. Every regular DLL that uses the extension DLL must call the exported initialization function.

If an extension DLL is only going to be used from an MFC application (.EXE) and never from a regular DLL, then it is sufficient to create the CDynLinkLibrary object in the extension DLL's DllMain. This is what the AppWizard extension DLL code does. When loading an extension DLL implicitly, DllMain loads and executes before the application ever starts. Any CDynLinkLibrary creations are wired into a default chain that the MFC DLL reserves for an MFC application.

Note that it is a bad idea to have multiple CDynLinkLibrary objects from one extension DLL in any one chain, especially if the extension DLL will be dynamically unloaded from memory. Do not call the initialization function more than once from any one module.

Sample Code

This sample code assumes that the regular DLL is implicitly linking to the extension DLL. This is accomplished by linking to the import library (.LIB) of the extension DLL when building the regular DLL.

These lines should be in the source of the extension DLL:

// YourExtDLL.cpp:

// standard MFC extension DLL routines
#include "afxdllx.h"

static AFX_EXTENSION_MODULE NEAR extensionDLL = { NULL, NULL };

extern "C" int APIENTRY
DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        // extension DLL one-time initialization.
        if (!AfxInitExtensionModule(extensionDLL, hInstance))
           return 0;
    }
    return 1;   // ok
}

// Exported DLL initialization is run in context of
// application or regular DLL
extern "C" void WINAPI InitYourExtDLL()
{
    // create a new CDynLinkLibrary for this app
    new CDynLinkLibrary(extensionDLL);

    // add other initialization here
}

Be sure to export the InitYourExtDLL function. This could be done using __declspec(dllexport), or in your DLL's .DEF file as follows:

// YourExtDLL.Def:
LIBRARY      YOUREXTDLL
CODE         PRELOAD MOVEABLE DISCARDABLE
DATA         PRELOAD SINGLE
EXPORTS
    InitYourExtDLL

Add a call to the InitInstance member of the CWinApp-derived object in each regular DLL using the extension DLL:

// YourRegularDLL.cpp:

class CYourRegularDLL : public CWinApp
{
public:
    virtual BOOL InitInstance(); // Initialization
    virtual int ExitInstance();  // Termination

    // nothing special for the constructor
    CYourRegularDLL(LPCTSTR pszAppName) : CWinApp(pszAppName) { }
};

BOOL CYourRegularDLL::InitInstance()
{
  // any DLL initialization goes here
    TRACE0("YOUR regular DLL initializing\n");

  // wire any extension DLLs into CDynLinkLibrary chain
    InitYourExtDLL();

    return TRUE;
}

What do you want to do?

  • Initialize an extension DLL

  • Initialize regular DLLs

What do you want to know more about?

  • Extension DLLs

  • Regular DLLs statically linked to MFC

  • Regular DLLs dynamically linked to MFC

  • Using MFC as Part of a DLL

  • DLL Version of MFC


Using __declspec(dllimport) and __declspec(dllexport)

Home | Overview | How Do I | FAQ | Details | Sample

The 32-bit edition of Visual C++ uses __declspec(dllimport) and __declspec(dllexport) to replace the __export keyword previously used in 16-bit versions of Visual C++.

You do not need to use __declspec(dllimport) for your code to compile correctly, but doing so allows the compiler to generate better code. The compiler is able to generate better code because it knows for sure whether a function exists in a DLL or not, so the compiler can produce code that skips a level of indirection that would normally be present in a function call that crossed a DLL boundary. However, you must use __declspec(dllimport) in order to import variables used in a DLL.

With the proper .DEF file EXPORTS section, __declspec(dllexport) is not required. __declspec(dllexport) was added to provide an easy way to export functions from an .EXE or .DLL without using a .DEF file.

The Win32 Portable Executable format is designed to minimize the number of pages that must be touched to fix imports. To do this, it places all the import addresses for any program in one place called the Import Address Table. This allows the loader to modify only one or two pages when accessing these imports.

Using _declspec(dllimport) for Function Calls

In the following code example, assume func1 is a function that resides in a DLL separate from the .EXE file that contains the main function.

Without __declspec(dllimport), given this code:

   void main(void)
   {
       func1();
   }

the compiler generates code that looks like this:

    call func1

and the linker translates the call into something like this:

    call 0x4000000         ; The address of 'func1'.

If func1 exists in another DLL, the linker can't resolve this directly because it has no way of knowing what the address of func1 is. In 16-bit environments, the linker adds this code address to a list in the .EXE that the loader would patch at run time with the correct address. In 32-bit environments, the linker generates a thunk of which it does know the address. The thunk looks like:

   0x40000000:    jmp DWORD PTR __imp_func1

Here __imp_func1 is the address for func1's slot in the import address table of the .EXE file. All the addresses are thus known to the linker. The loader only has to update the .EXE file's import address table at load time for everything to work correctly.

Therefore, using __declspec(dllimport) is better because if the linker does not generate a thunk if it is not required. Thunks make the code larger (on RISC systems, it can be several instructions) and can degrade your cache performance. If you tell the compiler the function is in a DLL, it can generate an indirect call for you.

So now this code:

   __declspec(dllimport) void func1(void);
   void main(void)
   {
       func1();
   }

generates this instruction:

   call DWORD PTR __imp_func1

There is no thunk and no jmp instruction, so the code is smaller and faster.

On the other hand, for function calls inside a DLL, you don't want to have to use an indirect call. You already know a function's address. Time and space is required to load and store the address of the function before an indirect call, so a direct call is always faster and smaller. You only want to use __declspec(dllimport) when calling DLL functions from the outside the DLL itself. Don't use __declspec(dllimport) on functions inside a DLL when building that DLL.

Using _declspec(dllexport)

Microsoft introduced __export in the 16-bit compiler version of Visual C++ to allow the compiler to generate the export names automatically and place them in a .LIB file. This .LIB file could then be used just like a static .LIB to link with a DLL.

Microsoft added __declspec(dllexport) to continue this convenience. Its purpose is to add the export directive to the object file so you don't need a .DEF file.

This convenience is most apparent when trying to export decorated C++ function names. There is no standard specification for name decoration, so the name of an exported function may change between compiler versions. If you use __declspec(dllexport), recompiling the DLL and dependent .EXE files is necessary only to account for any naming convention changes.

Many export directives, such as ordinals, NONAME, and PRIVATE, can be made only in a .DEF file, and there is no way to specify these attributes without a .DEF file. However, using __declspec(dllexport) in addition to using a .DEF file does not cause build errors.

As a reference, search through the Win32 WINBASE.H header file. It contains examples of __declspec(dllimport) usage.

Using __declspec(dllexport) and __declspec(dllimport) on Data

In the case of data, using __declspec(dllimport) is a convenience item that removes a layer of indirection. When you import data from a DLL, you still have to go through the import address table. In the Win32 days before __declspec(dllimport), this meant you had to remember to do an extra level of indirection when accessing data exported from the DLL:

   // project.h
   #ifdef _DLL     // If accessing the data from inside            //the DLL
      ULONG ulDataInDll;

   #else            // If accessing the data from                //outside the DLL
      ULONG *ulDataInDll;
   #endif

You would then export the data in your .DEF file:

   // project.def
   LIBRARY project
   EXPORTS
       ulDataInDll   CONSTANT

and access it outside the DLL:

   if (*ulDataInDll == 0L)
   {
      // Do stuff here
   }

When you mark the data as __declspec(dllimport), the compiler automatically generates the indirection code for you. You no longer have to worry about the steps above. As stated previously, do not use __declspec(dllimport) declaration on the data when building the DLL. Functions within the DLL will not use the import address table to access the data object; therefore, you will not have the extra level of indirection present.

To export the data automatically from the DLL, use this declaration:

   __declspec(dllexport) ULONG ulDataInDLL;

Using a .DEF File

If you choose to use __declspec(dllimport) along with a .DEF file, you should change the .DEF file to use DATA in place of CONSTANT to reduce the likelihood that incorrect coding will cause a problem:

   // project.def
   LIBRARY project
   EXPORTS
       ulDataInDll   DATA

The following table shows why:

Keyword | Emits in the import library | Exports
CONSTANT | _imp_ulDataInDll _ulDataInDll | _ulDataInDll
DATA | _imp_ulDataInDll | _ulDataInDll

Using __declspec(dllimport) and CONSTANT lists both the __imp_ version and the undecorated name in the .LIB DLL import library that is created to allow explicit linking. Using __declspec(dllimport) and DATA lists just the __imp_ version of the name.

If you use CONSTANT, either of the following code constructs could be used to access the ulDataInDll:

   __declspec(dllimport) ULONG ulDataInDll; /*prototype*/
   if (ulDataInDll == 0L)   /*sample code fragment*/

-or-

   ULONG *ulDataInDll;      /*prototype*/
   if (*ulDataInDll == 0L)  /*sample code fragment*/

However, if you use DATA in your .DEF file, only code compiled with the following definition can access the variable ulDataInDll:

  __declspec(dllimport) ULONG ulDataInDll;

  if (ulDataInDll == 0L)   /*sample code fragment*/

Using CONSTANT is more risky because if you forget to use the extra level of indirection, you could potentially access the import address table's pointer to the variable — not the variable itself. This type of problem can often manifest as an access violation because the import address table is currently made read-only by the Microsoft compiler and linkers.

The Current Visual C++ linker issues a warning if it sees CONSTANT in the .DEF file to account for this case. The only real reason to use CONSTANT is if you can't recompile some object file where the header file didn't list __declspec(dllimport) on the prototype.

What do you want to do?

  • Export from a DLL using .DEF files

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Determine which exporting method to use


Importing and Exporting Inline Functions

Home | Overview | How Do I | FAQ | Details | Sample

Imported functions can be defined as inline. The effect is roughly the same as defining a standard function inline; calls to the function are expanded into inline code, much like a macro. This is principally useful as a way of supporting C++ classes in a DLL that may inline some of their member functions for efficiency.

One feature of an imported inline function is that in C++, you can take its address. The compiler returns the address of the copy of the inline function residing in the DLL. Another feature of imported inline functions is that unlike global imported data, you can initialize static local data of the imported function.

Caution You should exercise care when providing imported inline functions because they can create the possibility of version conflicts. An inline function gets expanded into the application code; therefore, if you later rewrite the function, it does not get updated unless the application itself is recompiled. (Normally, DLL functions can be updated without rebuilding the applications that use them.)

What do you want to do?

  • Export from a DLL

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Determine which exporting method to use

  • Import into an application using __declspec(dllimport)


Mutual Imports

Home | Overview | How Do I | FAQ | Details | Sample

Exporting or importing to another executable file presents complications when the imports are mutual (or "circular"). For example, two DLLs import symbols from each other, similar to mutually-recursive functions.

The problem with mutually-importing executable files (usually DLLs) is that neither can be built without building the other first. Each build process requires, as input, an import library produced by the other build process.

The solution is to use the LIB utility with the /DEF option, which produces an import library without building the executable file. Using this utility, you can build all the import libraries you need, no matter how many DLLs are involved or how complicated the dependencies are.

The general solution for handling mutual imports is:

  1. Take each DLL in turn. (Any order is feasible, although some orders are more optimal.) If all the needed import libraries exist and are current, run LINK to build the executable file (DLL). This produces an import library. Otherwise, run LIB to produce an import library.

    Running LIB with the /DEF option produces an additional file with an .EXP extension. The .EXP file must be used later to build the executable file.

  2. After using either LINK or LIB to build all the import libraries, go back and run LINK to build any executable files that were not built in the previous step. Note that the corresponding .EXP file must be specified on the LINK line.

    If you had run the LIB utility earlier to produce an import library for DLL1, LIB would have produced the file DLL1.EXP as well. You must use DLL1.EXP as input to LINK when building DLL1.DLL.

The figure "Linking Two DLLs with Mutual Imports" below illustrates a solution for two mutually-importing DLLs, DLL1 and DLL2. Step 1 is to run LIB, with the /DEF option set, on DLL1. Step 1 produces DLL1.LIB, an import library, and DLL1.EXP. In step 2, the import library is used to build DLL2, which in turn produces an import library for DLL2's symbols. Step 3 builds DLL1, by using DLL1.EXP and DLL2.LIB as input. Note that an .EXP file for DLL2 is not necessary because LIB was not used to build DLL2's import library.

Linking Two DLLs with Mutual Imports

Limitations of _AFXEXT

You can use the _AFXEXT preprocessor symbol for your extension DLLs as long as you do not have multiple layers of extension DLLs. If you have extension DLLs which call or derive from classes in your own extension DLLs, which then derive from the MFC classes, you must use your own preprocessor symbol to avoid ambiguity.

The problem is that in Win32, you must explicitly declare any data as __declspec(dllexport) if it is to be exported from a DLL, and __declspec(dllimport) if it is to be imported from a DLL. When you define _AFXEXT, the MFC headers make sure that AFX_EXT_CLASS is defined correctly.

When you have multiple layers, one symbol such as AFX_EXT_CLASS is not sufficient, since an extension DLL may be exporting new classes as well as importing other classes from another extension DLL. In order to solve this problem, use a special preprocessor symbol which indicates that you are building the DLL itself versus using the DLL. For example, imagine two extension DLLs, A.DLL and B.DLL. They each export some classes in A.H and B.H, respectively. B.DLL uses the classes from A.DLL. The header files would look something like this:

// A.H
#ifdef A_IMPL
   #define CLASS_DECL_A   __declspec(dllexport)
#else
   #define CLASS_DECL_A   __declspec(dllimport)
#endif

class CLASS_DECL_A CExampleA : public CObject
{ ... class definition ... };

// B.H
#ifdef B_IMPL
   #define CLASS_DECL_B   __declspec(dllexport)
#else
   #define CLASS_DECL_B   __declspec(dllimport)
#endif

class CLASS_DECL_B CExampleB : public CExampleA
{ ... class definition .. };
.
.
.

When A.DLL is built, it is built with /D A_IMPL and when B.DLL is built, it is built with /D B_IMPL. By using separate symbols for each DLL, CExampleB is exported and CExampleA is imported when building B.DLL. CExampleA is exported when building A.DLL and imported when used by B.DLL (or some other client).

This type of layering cannot be done when using the built-in AFX_EXT_CLASS and _AFXEXT preprocessor symbols. The technique described above solves this problem in a manner not unlike the mechanism MFC itself uses when building its Active technologies, Database, and Network extension DLLs.

Not Exporting the Entire Class

When you are not exporting an entire class, you have to ensure that the necessary data items created by the MFC macros are exported correctly. This can be done by re-defining AFX_DATA to your specific class' macro. This should be done any time you are not exporting the entire class.

For example:

   // A.H
   #ifdef A_IMPL
       #define CLASS_DECL_A  _declspec(dllexport)
   #else
       #define CLASS_DECL_A  _declspec(dllimport)
   #endif

   #undef  AFX_DATA
   #define AFX_DATA CLASS_DECL_A

   class CExampleA : public CObject
   {
     DECLARE_DYNAMIC()
     CLASS_DECL_A int SomeFunction();
     //... class definition ...
   };

   #undef AFX_DATA
   #define AFX_DATA

What do you want to do?

  • Export from a DLL

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export and import using AFX_EXT_CLASS

  • Export C++ functions for use in C-language executables

  • Determine which exporting method to use

  • Import into an application using __declspec(dllimport)

What do you want to know more about?

  • The LIB utility and the /DEF option


Active Technology and DLLs

Home | Overview | How Do I | FAQ | Details | Sample

Active technology allows object servers to be completely implemented inside a DLL. This type of server is called an "in-process server." MFC does not completely support in-process servers for all the features of visual editing, mainly because Active technology does not provide a way for a server to hook into the container's main message loop. MFC requires access to the container application's message loop to handle accelerator keys and idle-time processing.

If you are writing an Automation server and your server has no user interface, you can make your server an in-process server and put it completely into a DLL.

What do you want to know more about?

  • Automation Servers


Automation in a DLL

Home | Overview | How Do I | FAQ | Details | Sample

When you choose the Automation option in AppWizard, the wizard provides you with the following:

  • A starter object description language (.ODL) file.

  • An include directive in the STDAFX.H file for AFXOLE.H.

  • An implementation of the DllGetClassObject function, which calls the AfxDllGetClassObject function.

  • An implementation of the DllCanUnloadNow function, which calls the AfxDllCanUnloadNow function.

  • An implementation of the DllRegisterServer function, which calls the COleObjectFactory::UpdateRegistryAll function.

What do you want to know more about?

  • Automation Servers


Naming Conventions for MFC DLLs

Home | Overview | How Do I | FAQ | Details | Sample

The DLLs and libraries included in MFC follow a structured naming convention. This makes it easier to know which DLL or library you should be using for which purpose.

The shared MFC DLL version of MFC comes in a number of different forms. These forms are named according to the convention MFC[O|D|N]x0[U][D].DLL (where x is the MFC version number) as detailed in the following table. The import libraries needed to build applications or extension DLLs that use these DLLs have the same base name as the DLL but have a .LIB extension.

Shared DLL Naming Convention

DLL | Description
MFCx0.DLL | MFC DLL, ANSI Release version
MFCx0U.DLL | MFC DLL, Unicode Release version
MFCx0D.DLL | MFC DLL, ANSI Debug version
MFCx0UD.DLL | MFC DLL, Unicode Debug version
MFCOx0D.DLL | MFC DLL for Active technologies, ANSI Debug version
MFCOx0UD.DLL | MFC DLL for Active technologies, Unicode Debug version
MFCDx0D.DLL | MFC DLL for database, ANSI Debug version
MFCDx0UD.DLL | MFC DLL for database, Unicode Debug version
MFCNx0D.DLL | MFC DLL for network (sockets), ANSI Debug version
MFCNx0UD.DLL | MFC DLL for network (sockets), Unicode Debug version
MFCSx0.LIB | MFC DLL, statically-linked code, Release version
MFCSx0D.LIB | MFC DLL, statically-linked code, Debug version

Note The ActiveX control DLLs OC[D]x0[U][D].DLL are gone. ActiveX control support is now included in the MFC DLL listed in the preceding table.

Note The MFCSx0[D].LIB libraries are used in conjunction with the DLL versions of MFC. These library files contain code that must be statically linked in the application or DLL.

If you are dynamically linking to the shared DLL version of MFC, whether it is from an application or from an extension DLL, you must include MFCx0.DLL with your product. If you require Unicode support in your application, include MFCx0U.DLL instead.

Note The MFCx0.DLL and MFCx0U.DLL Retail version of the DLLs contain Active technologies, database, and network support in a single DLL. The Debug version maintains separate DLLs for these functional areas.

If you are statically linking your DLL to MFC, you must link it with one of the static MFC libraries. These versions are named according to the convention [N|U]AFXCW[D].LIB as listed in the following table.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Static-Link Regular DLL Naming Conventions

DLL | Description
NAFXCW.LIB | MFC Static Link Library, Release version
NAFXCWD.LIB | MFC Static Link Library, Debug version
UAFXCW.LIB | MFC Static Link Library with Unicode support, Release version
UAFXCWD.LIB | MFC Static Link Library with Unicode support, Debug version

Note In earlier versions of MFC (before version 4.0), there were special DLL variants of the libraries with names in the form [N|U]AFXDW[D].LIB. These variants no longer exist. Use the versions listed in the preceding table.

For a list of DLLs included with Visual C++ that can be distributed with your applications, see the file REDISTRB.WRI in the \OS\System directory on the Visual C++ CD-ROM.

What do you want to know more about?

  • The naming convention for libraries

  • Redistributable files

  • Categories of redistributable files


Redistributable Files

Home | Overview | How Do I | FAQ | Details | Sample

Applications built with Microsoft Visual C++ may require a number of supporting dynamic-link libraries (DLLs), depending on the way the application was built. The conditions under which you may or may not redistribute these files are described in the separate License Agreement included in the Visual C++ product. This article details the DLLs that must be redistributed with different types of applications.

Visual C++ redistributable files are located in several directories on the Visual C++ CD-ROM. See the file REDISTRB.WRI in the \OS\System directory on the Visual C++ CD-ROM for the locations of the redistributable files. These files are not installed by Visual C++ Setup in a separate directory on your hard disk. However, depending on the setup options you choose, Visual C++ Setup may install some of these files in your Windows System directory. When you redistribute any of these files, you should copy them from the CD to your own distribution disk image, rather than from your hard disk, to make sure you are redistributing the correct version of the files.

What do you want to know more about?

  • Categories of redistributable files

  • Version checking of redistributable files

  • MFC/other DLL files

  • ODBC files


Categories of Redistributable Files

Home | Overview | How Do I | FAQ | Details | Sample

Redistributable files may be categorized as follows:

  • MFC/other DLL files

  • ODBC files

The following tables, "MFC/Other Files" and "32-bit ODBC Files," list and briefly describe each redistributable file.

MFC/Other Files

File | Description
\ANSI\CTL3D32.DLL | 3D controls support DLL for ANSI (use with Win32s)
CTL3D32.DLL | 3D controls support DLL
MFCx0.DLL | MFC core code (MBCS-enabled)
MFCx0U.DLL | MFC core code (Unicode-enabled)
MSVCRT.DLL | Shared DLL version of C run time

32-bit ODBC Files

File | Description
_BOOTSTP.EXE | Used by ODBC setup
_MSSETUP.EX_ | Used by ODBC setup
_MSSETUP.EXE | ODBC setup (same as SETUP.EXE)
CTL3D32.DLL | 3D controls support (required by ODBC)
DS16GT.DLL | ODBC driver setup 16-bit generic thunk DLL
DS32GT.DLL | ODBC driver setup 32-bit generic thunk DLL
INSTCAT.SQL | SQL Server stored procedures
MSVCRT40.DLL | See Caution below
ODBC.INF | File list for the ODBC installer
ODBC16GT.DLL | ODBC 16-bit generic thunk DLL 16-bit
ODBC32GT.DLL | ODBC 32-bit generic thunk DLL 32-bit
ODBC32.DLL | 32-bit ODBC driver manager
ODBCCP32.CPL | 32-bit ODBC control panel component
ODBCCP32.DLL | 32-bit ODBC installer/administrator
ODBCCR32.DLL | 32-bit ODBC cursor library
ODBCINST.HLP | ODBC 2.0 help file
ODBCINT.DLL | ODBC error messages and dialog boxes
SETUP.EXE | ODBC setup (run after MSVC setup)
SETUP.LST | ODBC setup (same as SETUP.EXE)

In addition, you must also redistribute DLLs to support specific OBDC drivers. The SQL Server drivers are listed in the following table. See ODBCJET.HLP in the \OS\System directory for the supporting files for other ODBC data sources, such as .MDB and .DBF files.

SQL Server ODBC Files

File | Description
CTL3D32.DLL | 3D controls support (required by ODBC)
DBNMPNTW.DLL | 32-bit SQL Server named-pipes network library
DRVSSRVR.HLP | 32-bit SQL Server driver help file
SQLSRV32.DLL | 32-bit SQL Server ODBC driver file

What do you want to know more about?

  • Version checking of redistributable files

  • MFC/other DLL files

  • ODBC files


Version Checking of Redistributable Files

Home | Overview | How Do I | FAQ | Details | Sample

Because other applications may redistribute earlier or later versions of the same files as your application, it is important that you install newer versions of the files over older versions on your user's system, but not older versions over newer versions. Typically, version checking is the responsibility of your setup program. If you do not have a setup program for your main application, then your application must manually check the version when installing the redistributable files on your user's system.

The programmatic technique for version checking varies, depending on which category of file you are redistributing:

  • For the MFC DLLs, use the version checking APIs available as a standard part of the Win32 API.

  • For the ODBC files, see "Installing ODBC Software" and "Configuring Data Sources," in the ODBC Programmer's Reference.

What do you want to know more about?

  • The Win32 version checking APIs


MFC/Other DLL Files

Home | Overview | How Do I | FAQ | Details | Sample

You can link your application or DLL with the MFC library either statically or dynamically.

Feature Only in Professional and Enterprise Editions Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

If you dynamically link your application to the MFC library, you will, at a minimum, need to redistribute MFCx0[U].DLL and MSVCRT.DLL, where x is the version number. MFCx0[U].DLL includes all of the basic framework classes. All MFC DLLs use the shared version of the C run-time library; thus, MSVCRT.DLL is required. If your application uses the MFC database classes, such as CRecordset and CRecordView, you will need to redistribute ODBC and any ODBC drivers that your application uses.

If you redistribute any of these MFC DLLs, be sure you distribute the Retail version rather than the Debug version. Debug versions of the DLLs may not be redistributed. (Debug versions of the MFC DLLs have a trailing "D" in their file names, such as in MFCx0D.DLL).

If you modify MFC in any way, you must rename the modified MFC DLL so it will not conflict with the MFC DLL that might be installed by other MFC applications on your user's system. This is not a recommended procedure. For more information, see Technical Note 33.


ODBC Files

Home | Overview | How Do I | FAQ | Details | Sample

Use the ODBC Installer DLL to install the ODBC files on your user's system from your application's setup program. The redistributable files include the ODBC Driver Manager and the various ODBC drivers included in \OS\System. For information, see "Installing ODBC Software" and "Configuring Data Sources," in the ODBC Programmer's Reference.


Calling DLL Functions from Visual Basic Applications

Home | Overview | How Do I | FAQ | Details | Sample

In order for Visual Basic applications (or applications in other languages such as Pascal or Fortran) to call functions in a C/C++ DLL, the functions must be exported using the correct calling convention without any name decoration done by the compiler. In Windows 3.x and 16-bit editions of Visual C++, you could use the _pascal keyword as part of the definition of the exported function. However, there is no _pascal keyword in the 32-bit editions of Visual C++. Instead the WINDEF.H header file has PASCAL defined as __stdcall. This creates the correct calling convention for the function (the called function cleans up the stack and parameters are passed from right to left) but decorates the function name differently. So, when __declspec(dllexport) is used on an exported function in a DLL, the decorated name is exported instead of the desired PASCAL style name, which is undecorated and all uppercase.

PASCAL name decoration is simply the undecorated symbol name in uppercase letters. The __stdcall name decoration prefixes the symbol name with an underscore (_) and appends the symbol with an at sign (@) character followed by the number of bytes in the argument list (the required stack space). So, the function when declared as:

   int  __stdcall func (int a, double b)

is decorated as:

   _func@12

The C calling convention (__cdecl) decorates the name as _func. Whereas the desired PASCAL style name is FUNC.

To get the decorated name, set the Generate Mapfile option in the Linker General category setting. Use of __declspec(dllexport) does the following:

  • If the function is exported with the C calling convention (_cdecl), it strips the leading underscore (_) when the name is exported.

  • If the function being exported does not use the C calling convention (for example, __stdcall ), it exports the decorated name.

So to simulate PASCAL name decoration and calling conventions, you must have the "Called Function stack clean-up" provided by using __stdcall and the undecorated uppercase name.

Because there is no way to override where the stack clean up occurs, you must use __stdcall. To undecorate names with __stdcall, you must specify them by using aliases in the EXPORTS section of the .DEF file. This is shown below for the following function declaration:

   int  __stdcall MyFunc (int a, double b);
   void __stdcall InitCode (void);

In the .DEF file:

   EXPORTS
      MYFUNC=_MyFunc@12
      INITCODE=_InitCode@0

For DLLs to be called by programs written in the 32-bit version of Visual Basic version 4.0, the alias technique shown in this article is needed in the .DEF file. If alias is done in the Visual Basic program, use of aliasing in the .DEF file is not necessary. It can be done on the Visual Basic program by adding an alias clause to the declare statement as shown here:

Declare Function MyFunc Lib "dlllibname" Alias "_MyFunc@12"  (...)
                                As Integer

The complete syntax for the Visual Basic declare statement follows:

[Public | Private ] Declare Function name Lib
     "libname" [Alias "aliasname" ] [([arglist])][As type]

Note A very good discussion (with example code) of calling a C DLL from Visual Basic can be found in the file VB4DLL.TXT in the VB directory.

  • Export from a DLL

  • Export from a DLL using .DEF files

  • Export from a DLL using __declspec(dllexport)

  • Export C++ functions for use in C-language executables

  • Determine which exporting method to use

What do you want to know more about?

  • Decorated names


Exception Handling Topics (General)

Home | Overview | How Do I | FAQ

Handling exceptional conditions makes your code more robust. Certain operations, including object creation and file input/output, are subject to failures that go beyond errors — out-of-memory conditions, for instance, can occur even when your program is running correctly. Anticipating and handling exceptions is a hallmark of solid code.

This article family explains the three exception handling mechanisms supplied by Visual C++.

What do you want to know more about?

General Exception Handling Knowledge

  • When to use exceptions

  • Exception Handling Topics (MFC)

  • Exception Handling Topics (C++) (without MFC)

  • Structured exception handling in C

  • C++ exception handling syntax

  • C++ exception examples

  • Catching and deleting exceptions

  • Exception handling overhead

More Specialized Topics

  • Exceptions in database programming

  • Exceptions in OLE programming

  • How MFC exception macros changed in MFC version 3.0

  • Using both MFC macros and C++ exceptions

  • Examining the contents of an MFC exception object

  • Freeing objects in an exception handler

  • Throwing exceptions from your own functions

  • Exceptions in constructors

  • Type-safe exception handling

  • What happens to unhandled exceptions

  • Mixing C and C++ exceptions

  • Converting from MFC exception macros to C++ exceptions


Exception Handling Topics (MFC)

Home | Overview | How Do I | FAQ

This article explains the exception-handling mechanisms available in MFC. Two mechanisms are available:

  • C++ exceptions, available in MFC version 3.0 and later

  • The MFC exception macros, available in MFC versions 1.0 and later

If you’re writing a new application using MFC, you should use the C++ mechanism. You can use the macro-based mechanism if your existing application already uses that mechanism extensively.

You can readily convert existing code to use C++ exceptions instead of the MFC exception macros. Advantages of converting your code and guidelines for doing so are described in the article Exceptions: Converting from MFC Exception Macros.

If you have already developed an application using the MFC exception macros, you can continue using these macros in your existing code, while using C++ exceptions in your new code. The article Exceptions: Changes to Exception Macros in Version 3.0 gives guidelines for doing so.

Note To enable C++ exception handling in your code, select Enable Exception Handling in the C++ Language category of the C/C++ tab of the Project Settings dialog box, or use the /GX compiler option. The default is /GX–, which disables exception handling.

This article covers the following topics:

  • When to use exceptions

  • MFC exception support

  • Further reading about exceptions

When to Use Exceptions

Three categories of outcomes can occur when a function is called during program execution: normal execution, erroneous execution, or abnormal execution. Each category is described below.

  • Normal execution

    The function may execute normally and return. Some functions return a result code to the caller, which indicates the outcome of the function. The possible result codes are strictly defined for the function and represent the range of possible outcomes of the function. The result code can indicate success or failure or can even indicate a particular type of failure that is within the normal range of expectations. For example, a file-status function can return a code that indicates that the file does not exist. Note that the term “error code” is not used because a result code represents one of many expected outcomes.

  • Erroneous execution

    The caller makes some mistake in passing arguments to the function or calls the function in an inappropriate context. This situation causes an error, and it should be detected by an assertion during program development. (For more information on assertions, see the article Diagnostics: The ASSERT Macro.)

  • Abnormal execution

    Abnormal execution includes situations where conditions outside the program’s control, such as low memory or I/O errors, are influencing the outcome of the function. Abnormal situations should be handled by catching and throwing exceptions.

Using exceptions is especially appropriate for abnormal execution.

MFC Exception Support

Whether you use the C++ exceptions directly or use the MFC exception macros, you will use CException or CException-derived objects that may be thrown by the framework or by your application.

MFC provides several predefined kinds of exceptions:

Exception class | Meaning
CMemoryException | Out-of-memory
CFileException | File exception
CArchiveException | Archive/Serialization exception
CNotSupportedException | Response to request for unsupported service
CResourceException | Windows resource allocation exception
CDaoException | Database exceptions (DAO classes)
CDBException | Database exceptions (ODBC classes)
COleException | OLE exceptions
COleDispatchException | Dispatch (automation) exceptions
CUserException | Exception that alerts the user with a message box, then throws a generic CException

Note MFC supports both C++ exceptions and the MFC exception macros. MFC does not directly support Windows NT structured exception handlers (SEH), as discussed in Exception Handling Topics (SEH).

Further Reading About Exceptions

The following articles explain using the class library for exception handing:

  • Exceptions: Catching and Deleting Exceptions

  • Exceptions: Examining Exception Contents

  • Exceptions: Freeing Objects in Exceptions

  • Exceptions: Throwing Exceptions from Your Own Functions

  • Exceptions: Database Exceptions

  • Exceptions: OLE Exceptions

The following articles compare the MFC exception macros with the C++ exception keywords and explain how you can adapt your code:

  • Exceptions: Changes to Exception Macros in Version 3.0

  • Exceptions: Converting from MFC Exception Macros

  • Exceptions: Using MFC Macros and C++ Exceptions


Exceptions: Changes to Exception Macros in Version 3.0

Home | Overview | How Do I | FAQ

This is an advanced topic.

In MFC version 3.0 and later, the exception-handling macros have been changed to use C++ exceptions. This article tells how those changes can affect the behavior of existing code that uses the macros.

This article covers the following topics:

  • Exception types and the CATCH macro

  • Re-throwing exceptions

Exception Types and the CATCH Macro

In earlier versions of MFC, the CATCH macro used MFC run-time type information to determine an exception’s type; the exception’s type is determined, in other words, at the catch site. With C++ exceptions, however, the exception’s type is always determined at the throw site by the type of the exception object that is thrown. This will cause incompatibilities in the rare case where the type of the pointer to the thrown object differs from the type of the thrown object.

The following example illustrates the consequence of this difference between MFC version 3.0 and earlier versions:

TRY
{
    THROW( (CException*) new CCustomException() );
}
CATCH( CCustomException, e )
{
    TRACE( "MFC 2.x will land here\n" );
}
AND_CATCH( CException, e )
{
    TRACE( "MFC 3.0 will land here\n" );
}
END_CATCH

This code behaves differently in version 3.0 because control always passes to the first catch block with a matching exception-declaration. The result of the throw expression

THROW((CException*)new CCustomException());

is thrown as a CException*, even though it is constructed as a CCustomException. The CATCH macro in MFC versions 2.5 and earlier uses CObject::IsKindOf to test the type at run time. Because the expression

e->IsKindOf( RUNTIME_CLASS( CException ) )

is true, the first catch block catches the exception. In version 3.0, which uses C++ exceptions to implement many of the exception-handling macros, the second catch block matches the thrown CException.

Code like this is uncommon. It usually appears when an exception object is passed to another function that accepts a generic CException*, performs “pre-throw” processing, and finally throws the exception.

To work around this problem, move the throw expression from the function to the calling code and throw an exception of the actual type known to the compiler at the time the exception is generated.

Re-Throwing Exceptions

A catch block cannot throw the same exception pointer that it caught.

For example, this code was valid in previous versions, but will have unexpected results with version 3.0:

TRY
{
    // Do something to throw an exception.
}
CATCH( CSomeException, e )
{
    THROW( e );    // Wrong. Use THROW_LAST() instead
}
END_TRY

Using THROW in the catch block causes the pointer e to be deleted, so that the outer catch site will receive an invalid pointer. Use THROW_LAST to re-throw e.

For related information, see Exceptions: Catching and Deleting Exceptions.


Exceptions: Catching and Deleting Exceptions

Home | Overview | How Do I | FAQ

The following instructions and examples show you how to catch and delete exceptions. For more information on the try, catch, and throw keywords, see Exception Handling Topics (C++).

Your exception handlers must delete exception objects they handle, because failure to delete the exception causes a memory leak whenever that code catches an exception.

Your catch block must delete an exception when:

  • The catch block throws a new exception.

    Of course, you must not delete the exception if you throw the same exception again:

    catch(CException* e)
{
    if (m_bThrowExceptionAgain)
        throw; // Do not delete e
}
  • Execution returns from within the catch block.

Note When deleting a CException, use the Delete member function to delete the exception. Do not use the delete keyword, because it can fail if the exception is not on the heap.

To catch and delete exceptions

  • Use the try keyword to set up a try block. Execute any program statements that might throw an exception within a try block.

    Use the catch keyword to set up a catch block. Place exception-handling code in a catch block. The code in the catch block is executed only if the code within the try block throws an exception of the type specified in the catch statement.

    The following skeleton shows how try and catch blocks are normally arranged:

    // Normal program statements
...

try
{
    // Execute some code that might throw an exception.
}
catch( CException* e )
{
    // Handle the exception here.
    // "e" contains information about the exception.
    e->Delete();
}

// Other normal program statements
...

    When an exception is thrown, control passes to the first catch block whose exception-declaration matches the type of the exception. You can selectively handle different types of exceptions with sequential catch blocks as listed below:

    try
{
    // Execute some code that might throw an exception.
}
catch( CMemoryException* e )
{
    // Handle the out-of-memory exception here.
}
catch( CFileException* e )
{
    // Handle the file exceptions here.
}
catch( CException* e )
{
    // Handle all other types of exceptions here.
}

For related information, see Exceptions: Converting from MFC Exception Macros.


Exceptions: Converting from MFC Exception Macros

Home | Overview | How Do I | FAQ

This is an advanced topic.

This article explains how to convert existing code written with Microsoft Foundation Class macros — TRY, CATCH, THROW, and so on — to use the C++ exception-handling keywords try, catch, and throw. Topics include:

  • Conversion advantages

  • Converting code with exception macros to use C++ exceptions

Advantages of Converting

You probably do not need to convert existing code, although you should be aware of differences between the macro implementations in MFC version 3.0 and the implementations in earlier versions. These differences and subsequent changes in code behavior are discussed in Exceptions: Changes to Exception Macros in Version 3.0.

The principal advantages of converting are:

  • Code that uses the C++ exception-handling keywords compiles to a slightly smaller .EXE or .DLL.

  • The C++ exception-handling keywords are more versatile: They can handle exceptions of any data type that can be copied (int, float, char, and so on), whereas the macros handle exceptions only of class CException and classes derived from it.

The major difference between the macros and the keywords is that code using the macros “automatically” deletes a caught exception when the exception goes out of scope. Code using the keywords does not, so you must explicitly delete a caught exception. For more information, see the article Exceptions: Catching and Deleting Exceptions.

Another difference is syntax. The syntax for macros and keywords differs in three respects:

  1. Macro arguments and exception declarations:

    A CATCH macro invocation has the following syntax:

    CATCH( exception_class, exception_object_pointer_name )

    Notice the comma between the class name and the object pointer name.

    The exception declaration for the catch keyword uses this syntax:

    catch( exception_type exception_name)

    This exception declaration statement indicates the type of exception the catch block handles.

  2. Delimitation of catch blocks:

    With the macros, the CATCH macro (with its arguments) begins the first catch block; the AND_CATCH macro begins subsequent catch blocks, and the END_CATCH macro terminates the sequence of catch blocks.

    With the keywords, the catch keyword (with its exception declaration) begins each catch block. There is no counterpart to the END_CATCH macro; the catch block ends with its closing brace.

  3. The throw expression:

    The macros use THROW_LAST to re-throw the current exception. The throw keyword, with no argument, has the same effect.

Doing the Conversion

To convert code using macros to use the C++ exception-handling keywords

  1. Locate all occurrences of the MFC macros TRY, CATCH, AND_CATCH, END_CATCH, THROW, and THROW_LAST.

  2. Replace or delete all occurrences of the following macros:

    TRY (Replace it with try)

    CATCH (Replace it with catch)

    AND_CATCH (Replace it with catch)

    END_CATCH (Delete it)

    THROW (Replace it with throw)

    THROW_LAST (Replace it with throw)

  3. Modify the macro arguments so that they form valid exception declarations.

    For example, change

    CATCH( CException, e )

    to

    catch( CException* e )
  4. Modify the code in the catch blocks so that it deletes exception objects as necessary. For more information, see the article Exceptions: Catching and Deleting Exceptions.

Here is an example of exception-handling code using MFC exception macros. Note that because the code in the following example uses the macros, the exception e is deleted automatically:

TRY
{
    // Do something to throw an exception.
}
CATCH(CException, e)
{
    if (m_bPassExceptionsUp)
        THROW_LAST();

    if (m_bReturnFromThisFunction)
        return;

    // Not necessary to delete the exception e.
}
END_CATCH

The code in the next example uses the C++ exception keywords, so the exception must be explicitly deleted:

try
{
    // Do something to throw an exception.
}
catch(CException* e)
{
    if (m_bPassExceptionsUp)
        throw;

    if (m_bThrowDifferentException)
    {
        e->Delete();
        throw new CMyOtherException;
    }

    if (m_bReturnFromThisFunction)
    {
        e->Delete();
        return;
    }

    e->Delete();
}

For related information, see Exceptions: Using MFC Macros and C++ Exceptions.


Exceptions: Using MFC Macros and C++ Exceptions

Home | Overview | How Do I | FAQ

This article discusses considerations for writing code that uses both the MFC exception-handling macros and the C++ exception-handling keywords.

This article covers the following topics:

  • Mixing exception keywords and macros

  • Try blocks inside catch blocks

Mixing Exception Keywords and Macros

You can mix MFC exception macros and C++ exception keywords in the same program. But you cannot mix MFC macros with C++ exception keywords in the same block because the macros delete exception objects automatically when they go out of scope, whereas code using the exception-handling keywords does not. For more information, see the article Exceptions: Catching and Deleting Exceptions.

The main difference between the macros and the keywords is that the macros “automatically” delete a caught exception when the exception goes out of scope. Code using the keywords does not; exceptions caught in a catch block must be explicitly deleted. Mixing macros and C++ exception keywords can cause memory leaks when an exception object is not deleted, or heap corruption when an exception is deleted twice.

The following code, for example, invalidates the exception pointer:

TRY
{
    TRY
    {
        // Do something to throw an exception.
    }
    CATCH(CException, e)  // The "inner" catch block
    {
        throw;  // Invalid attempt to throw exception
                 // to the outer catch block below.
    }
    END_CATCH
}
CATCH(CException, e)  // The "outer" catch block
{
     // Pointer e is invalid because
     // it was deleted in the inner catch block.
}
END_CATCH

The problem occurs because e is deleted when execution passes out of the “inner” CATCH block. Using the THROW_LAST macro instead of the THROW statement will cause the “outer” CATCH block to receive a valid pointer:

TRY
{
    TRY
    {
        // Do something to throw an exception.
    }
    CATCH(CException, e)  // The "inner" catch block
    {
        THROW_LAST(); // Throw exception to the outer catch block below.
    }
    END_CATCH
}
CATCH(CException, e)  // The "outer" catch block
{
     // Pointer e is valid because
     // THROW_LAST() was used.
}
END_CATCH

Try Blocks Inside Catch Blocks

You cannot re-throw the current exception from within a try block that is inside a CATCH block. The following example is invalid:

TRY
{
    // Do something to throw an exception.
}
CATCH(CException, e)
{
    try
    {
        throw;  // Wrong.  Causes e (the exception
                // being thrown) to be deleted.
    }
    catch(CException exception)
    {
    }
}
END_CATCH

For related information, see Exceptions: Examining Exception Contents.


Exceptions: Examining Exception Contents

Home | Overview | How Do I | FAQ

Although a catch block’s argument can be of almost any data type, the MFC functions throw exceptions of types derived from the class CException. To catch an exception thrown by an MFC function, then, you write a catch block whose argument is a pointer to a CException object (or an object derived from CException, such as CMemoryException). Depending on the exact type of the exception, you can examine the data members of the exception object to gather information about the specific cause of the exception.

For example, the CFileException type has the m_cause data member, which contains an enumerated type that specifies the cause of the file exception. Some examples of the possible return values are CFileException::fileNotFound and CFileException::readOnly.

The following example shows how to examine the contents of a CFileException. Other exception types can be examined similarly.

try
{
    // Do something to throw a file exception.
}
catch( CFileException* theException )
{
    if( theException->m_cause == CFileException::fileNotFound )
        TRACE( "File not found\n" );
    theException->Delete();
}

For related information, see Exceptions: Freeing Objects in Exceptions and Exceptions: Catching and Deleting Exceptions.


Exceptions: Freeing Objects in Exceptions

Home | Overview | How Do I | FAQ

This article explains the need and the method of freeing objects when an exception occurs. Topics include:

  • Handling the exception locally

  • Throwing exceptions after destroying objects

Exceptions thrown by the framework or by your application interrupt normal program flow. Thus, it is very important to keep close track of objects so that you can properly dispose of them in case an exception is thrown.

There are two primary methods to do this.

  • Handle exceptions locally using the try and catch keywords, then destroy all objects with one statement.

  • Destroy any object in the catch block before throwing the exception outside the block for further handling.

These two approaches are illustrated below as solutions to the following problematic example:

void SomeFunc()        // Problematic code
{
    CPerson* myPerson = new CPerson;

    // Do something that might throw an exception.
    myPerson->SomeFunc();

    // Now destroy the object before exiting.
    delete myPerson;
}

As written above, myPerson will not be deleted if an exception is thrown by SomeFunc. Execution jumps directly to the next outer exception handler, bypassing the normal function exit and the code that deletes the object. The pointer to the object goes out of scope when the exception leaves the function, and the memory occupied by the object will never be recovered as long as the program is running. This is a memory leak; it would be detected by using the memory diagnostics.

Handling the Exception Locally

The try/catch paradigm provides a defensive programming method for avoiding memory leaks and ensuring that your objects are destroyed when exceptions occur. For instance, the example shown earlier in this article could be rewritten as follows:

void SomeFunc()
{
    CPerson* myPerson = new CPerson;

    try
    {
        // Do something that might throw an exception.
        myPerson->SomeFunc();
    }
    catch( CException* e )
    {
        // Handle the exception locally
        e->Delete();
    }

    // Now destroy the object before exiting.
    delete myPerson;
}

This new example sets up an exception handler to catch the exception and handle it locally. It then exits the function normally and destroys the object. The important aspect of this example is that a context to catch the exception is established with the try/catch blocks. Without a local exception frame, the function would never know that an exception had been thrown and would not have the chance to exit normally and destroy the object.

Throwing Exceptions After Destroying Objects

Another way to handle exceptions is to pass them on to the next outer exception-handling context. In your catch block, you can do some cleanup of your locally allocated objects and then throw the exception on for further processing.

The throwing function may or may not need to deallocate heap objects. If the function always deallocates the heap object before returning in the normal case, then the function should also deallocate the heap object before throwing the exception. On the other hand, if the function does not normally deallocate the object before returning in the normal case, then you must decide on a case-by-case basis whether the heap object should be deallocated.

The following example shows how locally allocated objects can be cleaned up:

void SomeFunc()
{
    CPerson* myPerson = new CPerson;

    try
    {
        // Do something that might throw an exception.
        myPerson->SomeFunc();
    }
    catch( CException e )
    {
         // Destroy the object before passing exception on.
        delete myPerson;
        // Throw the exception to the next handler.
        throw;
    }

    // On normal exits, destroy the object.
    delete myPerson;
}

The exception mechanism automatically deallocates frame objects; the destructor of the frame object is also called.

If you call functions that can throw exceptions, you can use try/catch blocks to make sure that you catch the exceptions and have a chance to destroy any objects you have created. In particular, be aware that many MFC functions can throw exceptions.

For related information, see Exceptions: Catching and Deleting Exceptions.


Exceptions: Throwing Exceptions from Your Own Functions

Home | Overview | How Do I | FAQ

It is possible to use the MFC exception-handling paradigm solely to catch exceptions thrown by functions in MFC or other libraries. In addition to catching exceptions thrown by library code, you can throw exceptions from your own code if you are writing functions that can encounter exceptional conditions.

When an exception is thrown, execution of the current function is stopped and jumps directly to the catch block of the innermost exception frame. The exception mechanism bypasses the normal exit path from a function. Therefore, you must be sure to delete those memory blocks that would be deleted in a normal exit.

To throw an exception

  • Use one of the MFC helper functions, such as AfxThrowMemoryException. These functions throw a preallocated exception object of the appropriate type.

    In the following example, a function tries to allocate two memory blocks and throws an exception if either allocation fails:

    {
    char* p1 = (char*)malloc( SIZE_FIRST );
    if( p1 == NULL )
        AfxThrowMemoryException();
    char* p2 = (char*)malloc( SIZE_SECOND );
    if( p2 == NULL )
    {
        free( p1 );
        AfxThrowMemoryException();
    }

    // ... Do something with allocated blocks ...

    // In normal exit, both blocks are deleted.
    free( p1 );
    free( p2 );
}

    If the first allocation fails, you can simply throw the memory exception. If the first allocation is successful but the second one fails, you must free the first allocation block before throwing the exception. If both allocations succeed, you can proceed normally and free the blocks when exiting the function.

    – or –

  • Use a user-defined exception to indicate a problem condition. You can throw an item of any type, even an entire class, as your exception.

    The following example attempts to play a sound through a wave device and throws an exception if there is a failure.

    #define WAVE_ERROR -5
{
    // This Win32 API returns 0 if the sound cannot be played.
    // Throw an integer constant if it fails.
    if( !sndPlaySound("SIREN.WAV", SND_ASYNC) )
        throw WAVE_ERROR;
}

Note MFC’s default handling of exceptions applies only to pointers to CException objects (and objects of CException-derived classes). The example above bypasses MFC’s exception mechanism.


Exceptions: Exceptions in Constructors

Home | Overview | How Do I | FAQ

When throwing an exception in a constructor, clean up whatever objects and memory allocations you have made prior to throwing the exception, as explained in Exceptions: Throwing Exceptions from Your Own Functions.

Throwing an exception in a constructor is tricky, however, because the memory for the object itself has already been allocated by the time the constructor is called. There is no simple way to deallocate the memory occupied by the object from within the constructor for that object. Thus, you will find that throwing an exception in a constructor will result in the object remaining allocated. For a discussion of how to detect objects in your program that have not been deallocated, see the article Diagnostics: Detecting Memory Leaks.

If you are performing operations in your constructor that can fail, it might be a better idea to put those operations into a separate initialization function rather than throwing an exception in the constructor. That way, you can safely construct the object and get a valid pointer to it. Then you can call the initialization function for the object. If the initialization function fails, you can delete the object directly.

For more information, see Exceptions: Freeing Objects in Exceptions.


Exceptions: Database Exceptions

Home | Overview | How Do I | FAQ

This article explains how to handle database exceptions. Most of the material in this article applies whether you are working with the MFC classes for Open Database Connectivity (ODBC) or the MFC classes for Data Access Objects (DAO). Material specific to one or the other model is explicitly marked. Topics include:

  • Approaches to exception handling

  • A database exception-handling example

Approaches to Exception Handling

The approach is the same whether you are working with DAO or ODBC.

You should always write exception handlers to handle exceptional conditions.

The most pragmatic approach to catching database exceptions is to test your application with exception scenarios. Determine the likely exceptions that might occur for an operation in your code, and force the exception to occur. Then examine the trace output to see what exception is thrown, or examine the returned error information in the debugger. This lets you know which return codes you’ll see for the exception scenarios you are using.

Error Codes Used for ODBC Exceptions

In addition to return codes defined by the framework, which have names of the form AFX_SQL_ERROR_XXX, some CDBExceptions are based on ODBC return codes. The return codes for such exceptions have names of the form SQL_ERROR_XXX.

The return codes — both framework-defined and ODBC-defined — that the database classes can return are documented under the m_nRetCode data member of class CDBException. Additional information about return codes defined by ODBC is available in the ODBC SDK Programmer’s Reference on the MSDN Library CD.

Error Codes Used for DAO Exceptions

For DAO exceptions, more information is typically available. You can access error information through three data members of a caught CDaoException object:

m_pErrorInfo contains a pointer to a CDaoErrorInfo object that encapsulates error information in DAO’s collection of error objects associated with the database.

m_nAfxDaoError contains an extended error code from the MFC DAO classes. These error codes, which have names of the form AFX_DAO_ERROR_XXX, are documented under the data member in CDaoException.

m_scode contains an OLE SCODE from DAO, if applicable. You’ll seldom need to work with this error code, however. Usually more information is available in the other two data members. See the data member for more about SCODE values.

Additional information about DAO errors, the DAO Error object type, and the DAO Errors collection is available under class CDaoException and in the topics Trappable Data Access Errors and Error Object, Errors Collection in DAO Help.

A Database Exception-Handling Example

The following example attempts to construct a CRecordset-derived object on the heap with the new operator, and then open the recordset (for an ODBC data source). For a similar example for the DAO classes, see “DAO Exception Example” below.

ODBC Exception Example

The Open member function could throw an exception (of type CDBException for the ODBC classes), so this code brackets the Open call with a try block. The subsequent catch block will catch a CDBException. You could examine the exception object itself, called e, but in this case it is enough to know that the attempt to create a recordset has failed. The catch block displays a message box and cleans up by deleting the recordset object.

CRecordset* CSectionView::OnGetRecordset()
{
    if ( m_pSet != NULL )
        return m_pSet;        // Recordset already allocated

    m_pSet = new CSectionSet( NULL );
    try
    {
        m_pSet->Open( );
    }
    catch( CDBException* e )
    {
        AfxMessageBox( e->m_strError,
                      MB_ICONEXCLAMATION );
        // Delete the incomplete recordset object
        delete m_pSet;
        m_pSet = NULL;
        e->Delete();
    }
    return m_pSet;
}

DAO Exception Example

The DAO example is similar to the example for ODBC, but you can typically retrieve more kinds of information. The following code also attempts to open a recordset. If that attempt throws an exception, you can examine a data member of the exception object for error information. As with the previous ODBC example, it is probably enough to know that the attempt to create a recordset failed.

CDaoRecordset* CSectionView::OnGetRecordset()
{
    if ( m_pSet != NULL )
        return m_pSet;  // Recordset already allocated

    m_pSet = new CSectionSet( NULL );
    try
    {
        m_pSet->Open( );
    }
    catch( CDaoException* e )
    {
         AfxMessageBox(
                e->m_pErrorInfo->m_strDescription,
                MB_ICONEXCLAMATION );
        // Delete the incomplete recordset object
        delete m_pSet;
        m_pSet = NULL;
        e->Delete();
    }
    return m_pSet;
}

This code gets an error message string from the m_pErrorInfo member of the exception object. MFC fills this member when it throws the exception.

For a discussion of the error information returned by a CDaoException object, see classes CDaoException and CDaoErrorInfo.

When you are working with Microsoft Jet (.mdb) databases, and in most cases when you are working with ODBC, there will be only one error object. In the rare case when you are using an ODBC data source and there are multiple errors, you can loop through DAO’s Errors collection based on the number of errors returned by CDaoException::GetErrorCount. Each time through the loop, call CDaoException::GetErrorInfo to refill the m_pErrorInfo data member.


Exceptions: OLE Exceptions

Home | Overview | How Do I | FAQ

The techniques and facilities for handling exceptions in OLE are the same as those for handling other exceptions. For further information on exception handling, see the article Exception Handling Topics.

All exception objects are derived from the abstract base class CException. MFC provides two classes for handling OLE exceptions:

  • COleException For handling general OLE exceptions.

  • COleDispatchException For generating and handling OLE dispatch (automation) exceptions.

The difference between these two classes is the amount of information they provide and where they are used. COleException has a public data member that contains the OLE status code for the exception. COleDispatchException supplies more information, including the following:

  • An application-specific error code

  • An error description, such as “Disk full”

  • A Help context that your application can use to provide additional information for the user

  • The name of your application’s Help file

  • The name of the application that generated the exception

COleDispatchException provides more information so that it can be used with products like Microsoft Visual Basic. The verbal error description can be used in a message box or other notification; the Help information can be used to help the user respond to the conditions that caused the exception.

Two global functions correspond to the two OLE exception classes: AfxThrowOleException and AfxThrowOleDispatchException. Use them to throw general OLE exceptions and OLE dispatch exceptions, respectively.


Exception Handling Topics (C++)

Home | Overview | How Do I | FAQ

The C++ language provides built-in support for handling anomalous situations, known as “exceptions,” which may occur during the execution of your program. With C++ exception handling, your program can communicate unexpected events to a higher execution context that is better able to recover from such abnormal events. These exceptions are handled by code that is outside the normal flow of control.

Note In these articles, the terms “structured exception handling” and “structured exception” (or “C exception”) refer exclusively to the Win32 structured exception handling mechanism provided by Windows 95 and Windows NT. All other references to exception handling (or “C++ exception”) refer to the C++ exception handling mechanism.

Note MFC now uses C++ exception handling. The older MFC exception macros, if you still use them, evaluate to C++ exception keywords. See Exceptions: Changes to Exception Macros in Version 3.0.

Unlike the Win32 structured exception handling mechanism, the language itself provides support for C++ exception handling. These articles describe the Microsoft implementation of C++ exception handling, which is based on the ISO WG21/ANSI X3J16 working papers towards the evolving standard for C++.

For C++ programs, you should use C++ exception handling rather than structured exception handling. While structured exception handling works in C++ programs, you can ensure that your code is more portable by using C++ exception handling. The C++ exception handling mechanism is more flexible, in that it can handle exceptions of any type. C exceptions are always of type unsigned int.

Using C++ Exceptions

In C++, the process of raising an exception is called “throwing” an exception. A designated exception handler then “catches” the thrown exception.

To enable C++ exception handling in your code, open the Project Settings dialog box, select the C/C++ tab, select C++ Language in the Category box, and select Enable Exception Handling; or use the /GX compiler option. The default is /GX-, which disables exception handling unwind semantics.

Note As of version 4.0, the Microsoft Foundation Class Library (MFC), which is included with Visual C++, uses the C++ exception handling mechanism. Although you are encouraged to use C++ exception handling in new code, MFC version 4.0 and later retains the macros from previous versions of MFC so that old code will not be broken. The macros and the new mechanism can be combined as well. For information on mixing macros and C++ exception handling and on converting old code to use the new mechanism, see the articles Exceptions: Macros and C++ Exceptions, and Exceptions: Converting from MFC Exception Macros.

What do you want to know more about?

  • Exception handling syntax

  • Exception handling: default synchronous exception model

  • Type-safe exception handling

  • C++ exception examples

  • Unhandled exceptions

  • Order of handlers

  • Mixing C and C++ exceptions

  • Exception handling overhead


Exception Handling Syntax

Home | Overview | How Do I | FAQ

The structure for C++ exception handling is represented by the following syntax:

try-block :
try compound-statement handler-list

handler-list :
handler handler-listopt

handler :
catch ( exception-declaration ) compound-statement

exception-declaration :
type-specifier-list declarator
type-specifier-list abstract-declarator
type-specifier-list
...

throw-expression :
throw assignment-expressionopt

The compound-statement after the try clause is the guarded section of code. The throw-expression throws an exception. The compound-statement after the catch clause is the exception handler, and catches the exception thrown by the throw-expression. The exception-declaration statement after the catch clause indicates the type of exception the clause handles. The type can be any valid data type, including a C++ class.

If the exception-declaration statement is an ellipsis (...), the catch clause handles any type of exception, including C exceptions as well as system-generated and application-generated exceptions. This includes exceptions such as memory protection, divide-by-zero, and floating-point violations. An ellipsis catch handler must be the last handler for its try block.

The operand of throw is syntactically similar to the operand of a return statement.

Microsoft Specific —>

Microsoft C++ does not support the function exception specification mechanism, as described in section 15.4 of the ANSI C++ draft.

END Microsoft Specific


Exception Handling: Default Synchronous Exception Model

Home | Overview | How Do I | FAQ

In previous versions of Visual C++, the C++ exception handling mechanism supported asynchronous (hardware) exceptions by default. Under the asynchronous model, the compiler assumes any instruction may generate an exception.

With the new synchronous exception model, now the default, exceptions can be thrown only with a throw statement. Therefore, the compiler can assume that exceptions happen only at a throw statement or at a function call. This model allows the compiler to eliminate the mechanics of tracking the lifetime of certain unwindable objects, and to significantly reduce the code size, if the objects’ lifetimes do not overlap a function call or a throw statement. The two exception handling models, synchronous and asynchronous, are fully compatible and can be mixed in the same application.

Catching hardware exceptions is still possible with the synchronous model. However, some of the unwindable objects in the function where the exception occurs may not get unwound, if the compiler judges their lifetime tracking mechanics to be unnecessary for the synchronous model.

See the /GX and /EH compiler options for information on enabling exception handling.


Type-Safe Exception Handling

Home | Overview | How Do I | FAQ

C++ exception handling supports type-safe exception handlers. C exceptions are always identified by an unsigned int. With C++ exception handling, you can specify that exceptions of a particular type (including C++ objects) are caught by a handler that matches the type of the exception being thrown.


C++ Exception Examples

Home | Overview | How Do I | FAQ

The real power of C++ exception handling lies not only in its ability to deal with exceptions of varying types, but also in its ability to automatically call destructor functions during stack unwinding for all local objects constructed before the exception was thrown.

The context which exists between the throw site and the catch handler is referred to as the “exception stack frame.” This frame may contain objects with destructor semantics. If an exception is thrown during execution of the guarded section or in any routine the guarded section calls (directly or indirectly), an exception object is created from the object created by the throw operand. (This implies that a copy constructor may be involved.) At this point, the compiler looks for a catch clause in a higher execution context that can handle an exception of the type thrown, or a catch handler that can handle any type of exception. The catch handlers are examined in order of their appearance following the try block. If no appropriate handler is found, the next dynamically enclosing try block is examined. This process continues until the outermost enclosing try block is examined.

If a matching handler is still not found, or if an exception occurs while unwinding but before the handler gets control, the predefined run-time function terminate is called. If an exception occurs after throwing the exception but before the unwind begins, the terminate function is called. You can install a custom termination function to handle such situations. See Unhandled Exceptions for more information.

The following example demonstrates C++ exception handling using classes with destructor semantics. It declares two C++ classes; one (class CTest) for defining the exception object itself, and the second (class CDtorDemo) for demonstrating the destruction of a separate frame object during stack unwinding:

#include <iostream.h>

void MyFunc( void );

class CTest
{
public:
    CTest(){};
    ~CTest(){};
    const char *ShowReason() const { return "Exception in CTest class."; }

};

class CDtorDemo
{
public:
    CDtorDemo();
    ~CDtorDemo();
};

CDtorDemo::CDtorDemo()
{
    cout << "Constructing CDtorDemo." << endl;
}

CDtorDemo::~CDtorDemo()
{
    cout << "Destructing CDtorDemo." << endl;
}

void MyFunc()
{

    CDtorDemo D;
    cout<< "In MyFunc(). Throwing CTest exception." << endl;
    throw CTest();
}

int main()
{
    cout << "In main." << endl;
    try
    {
        cout << "In try block, calling MyFunc()." << endl;
        MyFunc();
    }
    catch( CTest E )
    {
        cout << "In catch handler." << endl;
        cout << "Caught CTest exception type: ";
        cout << E.ShowReason() << endl;
    }
    catch( char *str )
    {
        cout << "Caught some other exception: " << str << endl;
    }
    cout << "Back in main. Execution resumes here." << endl;
    return 0;

}

If a matching catch handler is found, and it catches by value, its formal parameter is initialized by copying the exception object. If it catches by reference, the parameter is initialized to refer to the exception object. After the formal parameter is initialized, the process of “unwinding the stack” begins. This involves the destruction of all automatic objects that were constructed (but not yet destructed) between the beginning of the try block associated with the catch handler and the exception’s throw site. Destruction occurs in reverse order of construction. The catch handler is executed and the program resumes execution following the last handler (that is, the first statement or construct that is not a catch handler).

This is the output from the preceding example:

In main.
In try block, calling MyFunc().
Constructing CDtorDemo.
In MyFunc(). Throwing CTest exception.
Destructing CDtorDemo.
In catch handler.
Caught CTest exception type: Exception in CTest class.
Back in main. Execution resumes here.

Note the declaration of the exception parameter in both catch handlers:

catch( CTest E )
{ // ... }
catch( char *str )
{ // ... }

You do not need to declare this parameter; in many cases it may be sufficient to notify the handler that a particular type of exception has occurred. However, if you do not declare an exception object in the exception declaration, you will not have access to the object in the catch handler clause. For example:

catch( CTest )
{
    // No access to a CTest exception object in this handler.
}

A throw expression with no operand re-throws the exception currently being handled. Such an expression should appear only in a catch handler or in a function called from within a catch handler. The re-thrown exception object is the original exception object (not a copy). For example:

try
{
    throw CSomeOtherException();
}
catch(...)      // Handle all exceptions
{
    // Respond (perhaps only partially) to exception
    //...

    throw;      // Pass exception to some other handler
}


Catchable Types

Because C++ enables you to throw exceptions of any type, you need to determine which catch handlers can catch an exception of a specific class type. A C++ exception can be caught by a catch handler that specifies the same type as the thrown exception, or by a handler that can catch any type of exception. An exception can also be caught by a catch handler that uses a reference to the same type as the thrown exception.

If the type of thrown exception is a class, which also has a base class (or classes), it can be caught by handlers that accept base classes of the exception’s type, as well as references to bases of the exception’s type. Note that when an exception is caught by a reference, it is bound to the actual thrown exception object; otherwise, it is a copy (much the same as an argument to a function).

When an exception is thrown, it may be caught by the following types of catch handlers:

  • A handler that can accept any type (using the ellipsis syntax).

  • A handler that accepts the same type as the exception object; because it is a copy, const and volatile modifiers are ignored.

  • A handler that accepts a reference to the same type as the exception object.

  • A handler that accepts a reference to a const or volatile form of the same type as the exception object.

  • A handler that accepts a base class of the same type as the exception object; since it is a copy, const and volatile modifiers are ignored. The catch handler for a base class must not precede the catch handler for the derived class.

  • A handler that accepts a reference to a base class of the same type as the exception object.

  • A handler that accepts a reference to a const or volatile form of a base class of the same type as the exception object.

  • A handler that accepts a pointer to which a thrown pointer object can be converted via standard pointer conversion rules.


Unhandled Exceptions

Home | Overview | How Do I | FAQ

If a matching catch handler (or ellipsis catch handler) cannot be found for the current exception, the predefined terminate run-time function is called. (You can also explicitly call terminate in any of your handlers.) The default action of terminate is to call abort. If you want terminate to call some other function in your program before exiting the application, call the set_terminate function with the name of the function to be called as its single argument. You can call set_terminate at any point in your program. The terminate routine always calls the last function given as an argument to set_terminate.

The following example code throws a char * exception, but does not contain a handler designated to catch exceptions of type char *. The call to set_terminate instructs terminate to call term_func:

#include <eh.h>      // For function prototypes
#include <iostream.h>
#include <process.h>

void term_func()
{
    //...
    cout << "term_func was called by terminate." << endl;
    exit( -1 );
 }
int main()
{
    try
    {
        // ...
        set_terminate( term_func );
        // ...
        throw "Out of memory!"; // No catch handler for this exception
    }
    catch( int )
    {
        cout << "Integer exception raised." << endl;
    }
    return 0;
}

After performing any desired cleanup tasks, the term_func function should terminate the program or current thread, ideally by calling exit. If it doesn’t, and instead returns to its caller, abort is called.


Order of Handlers

Home | Overview | How Do I | FAQ

The order in which catch handlers appear is significant, because handlers for a given try block are examined in order of their appearance. For example, it is an error to place the handler for a base class before the handler for a derived class. After a matching catch handler is found, subsequent handlers are not examined. As a result, an ellipsis catch handler must be the last handler for its try block. For example:

// ...
try
{
    // ...
}
catch( ... )
{
    // Handle exception here.
}
// Error: the next two handlers are never examined.
catch( const char * str )
{
    cout << "Caught exception: " << str << endl;
}
catch( CExcptClass E )
{
    // Handle CExcptClass exception here.
}

In this example, the ellipsis catch handler is the only handler that is examined.


Mixing C and C++ Exceptions

Home | Overview | How Do I | FAQ

If you want to write more portable code, using structured exception handling in a C++ program is not recommended. However, you may sometimes want to mix C and C++ source code, and need some facility for handling both kinds of exceptions. Because a structured exception handler has no concept of objects or typed exceptions, it cannot handle exceptions thrown by C++ code; however, C++ catch handlers can handle C exceptions. As such, C++ exception handling syntax (try, throw, catch) is not accepted by the C compiler, but structured exception handling syntax (__try, __except, __finally) is supported by the C++ compiler.

If you mix C and C++ exceptions, note the following:

  1. C++ exceptions and C exceptions cannot be mixed within the same function.

  2. Termination handlers (__finally blocks) are always executed, even during unwinding after an exception is thrown.

  3. C++ exception handling can catch and preserve unwind semantics in all modules compiled with the /GX compiler option (this option enables unwind semantics).

  4. There may be some situations in which destructor functions are not called for all objects. For example, if a C exception occurs while attempting to make a function call through an uninitialized function pointer, and that function takes as parameters objects that were constructed before the call, those objects will not have their destructors called during stack unwind.

What do you want to know more about?

  • Using setjmp or longjmp in C++ programs

  • Differences between SEH and C++ EH


Using setjmp/longjmp

Home | Overview | How Do I | FAQ

Do not use setjmp and longjmp in C++ programs; these functions do not support C++ object semantics. Also, using these functions in C++ programs may degrade performance by preventing optimization on local variables. Use the C++ exception handling try/catch constructs instead.

If you do use setjmp/longjmp in a C++ program, the interaction between these functions and C++ exception handling requires that you include SETJMP.H or SETJMPEX.H. Destructors for local objects will be called during the stack unwind if you compile with the /GX (Enable Exception Handling) option. Also, if you intend your code to be portable, do not rely on correct destruction of frame-based objects when executing a nonlocal goto using a call to longjmp.


Exception Handling Differences

Home | Overview | How Do I | FAQ

The major difference between structured exception handling and C++ exception handling is that the C++ exception handling model deals in types, while the C structured exception handling model deals with exceptions of one type — specifically, unsigned int. That is, C exceptions are identified by an unsigned integer value, whereas C++ exceptions are identified by data type. When an exception is raised in C, each possible handler executes a filter that examines the C exception context and determines whether to accept the exception, pass it to some other handler, or ignore it. When an exception is thrown in C++, it may be of any type.

A second difference is that the C structured exception handling model is referred to as “asynchronous” in that exceptions occur secondary to the normal flow of control. The C++ exception handling mechanism is fully “synchronous,” which means that exceptions occur only when they are thrown.

If a C exception is raised in a C++ program, it can be handled by a structured exception handler with its associated filter or by a C++ catch handler, whichever is dynamically nearer to the exception context. For example, the following C++ program raises a C exception inside a C++ try context:

#include <iostream.h>

void SEHFunc( void );

int main()
{
    try
    {
        SEHFunc();
    }
    catch( ... )
    {
        cout << "Caught a C exception."<< endl;
    }
    return 0;
}
void SEHFunc()
{
    __try
    {
        int x, y = 0;
        x = 5 / y;
    }
    __finally
    {
        cout << "In finally." << endl;
    }
}

This is the output from the preceding example:

In finally.
Caught a C exception.

C Exception Wrapper Class

In a simple example like the above, the C exception can be caught only by an ellipsis (...) catch handler. No information about the type or nature of the exception is communicated to the handler. While this method works, in some cases you may need to define a transformation between the two exception handling models so that each C exception is associated with a specific class. To do this, you can define a C exception "wrapper" class, which can be used or derived from in order to attribute a specific class type to a C exception. By doing so, each C exception can be handled by a C++ catch handler more separately than in the preceding example.

Your wrapper class might have an interface consisting of some member functions that determine the value of the exception, and that access the extended exception context information provided by the C exception model. You might also want to define a default constructor and a constructor that accepts an unsigned int argument (to provide for the underlying C exception representation), and a bitwise copy constructor. The following is a possible implementation of a C exception wrapper class:

class SE_Exception
{
private:
    SE_Exception() {}
    SE_Exception( SE_Exception& ) {}
    unsigned int nSE;
public:
    SE_Exception( unsigned int n ) : nSE( n ) {}
    ~SE_Exception() {}
    unsigned int getSeNumber() { return nSE; }
};

To use this class, you install a custom C exception translation function that is called by the internal exception handling mechanism each time a C exception is thrown. Within your translation function, you can throw any typed exception (perhaps an SE_Exception type, or a class type derived from SE_Exception) that can be caught by an appropriate matching C++ catch handler. The translation function can simply return, which indicates that it did not handle the exception. If the translation function itself raises a C exception, terminate is called.

To specify a custom translation function, call the _set_se_translator function with the name of your translation function as its single argument. The translation function that you write is called once for each function invocation on the stack that has try blocks. There is no default translation function; if you do not specify one by calling _set_se_translator, the C exception can only be caught by an ellipsis catch handler.

For example, the following code installs a custom translation function, then raises a C exception that is wrapped by the SE_Exception class:

#include <stdio.h>
#include <eh.h>
#include <windows.h>

class SE_Exception {
private:
    SE_Exception() {}
    SE_Exception( SE_Exception& ) {}
    unsigned int nSE;
public:
    SE_Exception(unsigned int n) : nSE(n) {}
    ~SE_Exception() {}
    unsigned int getSeNumber() { return nSE; }
};

void SEFunc(void);
void trans_func( unsigned, _EXCEPTION_POINTERS*);

int main()
{
    _set_se_translator( trans_func );
    try
    {
        SEFunc();
    }
    catch( SE_Exception e )
    {
        printf( "Caught a __try exception with SE_Exception.\n" );
        printf( "nSE = 0x%x\n", e.getSeNumber() );
    }
    return 0;
}
void SEFunc()
{
    __try
    {
        int x, y=0;
        x = 5 / y;
    }
    __finally
    {
        printf( "In finally\n" );
    }
}
void trans_func( unsigned int u, _EXCEPTION_POINTERS* pExp )
{
    printf( "In trans_func.\n" );
    throw SE_Exception( u );
}


Exception Handling Overhead

Home | Overview | How Do I | FAQ

The extra overhead associated with the C++ exception handling mechanism may increase the size of executable files and slow program execution time. The /GX compiler option enables C++ exception handling and unwind semantics. If you are not using C++ exception handling in your program and you want to eliminate the associated overhead, you can use the /GX- compiler option to turn off exception handling and unwind semantics. Note that /GX- is the default.

Because of the nature of exception handling and the extra overhead involved, exceptions should be used only to signal the occurrence of unusual or unanticipated program events. Exception handlers should not be used to redirect the program’s normal flow of control. For example, an exception should not be thrown in cases of potential logic or user input errors, such as the overflow of an array boundary. In these cases, simply returning an error code may be simpler and more concise. Judicious use of exception handling constructs makes your program easier to maintain and your code more readable.

For more information about C++ exception handling, see the Annotated C++ Reference Manual by Margaret Ellis and Bjarne Stroustrup.


Exception Handling Topics (SEH)

Home | Overview | How Do I | FAQ

Windows 95 and Windows NT support a robust approach to handling exceptions, called structured exception handling, which involves cooperation of the operating system but also has direct support in the programming language.

An “exception” is an event that is unexpected or disrupts the ability of the process to proceed normally. Exceptions can be detected by both hardware and software. Hardware exceptions include dividing by zero and overflow of a numeric type. Software exceptions include those you detect and signal to the system by calling the RaiseException function, and special situations detected by Windows 95 and Windows NT.

You can write more reliable code with structured exception handling. You can ensure that resources, such as memory blocks and files, are properly closed in the event of unexpected termination. You can also handle specific problems, such as insufficient memory, with concise, structured code that doesn’t rely on goto statements or elaborate testing of return codes.

Note These articles describe structured exception handling for the C programming language. Although structured exception handling can also be used with C++, the new C++ exception handling method should be used for C++ programs. See Using Structured Exception Handling with C++ for information on special considerations.

How Structured Exception Handling Works

The traditional approach to exception handling involves passing error codes: one function detects an error and passes an error code to its caller. This process may continue through many levels, until the error is communicated to the function that can properly respond to the error. If there is a weak link in the chain of function calls, the whole procedure fails.

Structured exception handling avoids this propagation of error codes. Its distinctive feature is that after an exception handler is installed, it can handle the exception no matter how many other functions are called. Thus, function A can handle an exception raised inside a function called by A.

What do you want to know more about?

  • Exception handlers and termination handlers.

  • Writing an exception handler.

  • Writing a termination handler.

  • Using structured exception handling with C++.


Exception Handlers and Termination Handlers

Home | Overview | How Do I | FAQ

The previous section used the term “exception handlers” in a generic sense, but there are actually two kinds:

  • Exception handlers, which can respond to or dismiss the exception

  • Termination handlers, which are called when an exception causes termination inside a block of code

These two types of handlers are distinct, yet they are closely related through a process called “unwinding the stack.” When an exception occurs, Windows 95 and Windows NT look for the most recently installed exception handler that is currently active. The handler can do one of three things:

  • Pass control to other handlers (fail to recognize the exception).

  • Recognize but dismiss the exception.

  • Recognize and handle the exception.

The exception handler that recognizes the exception may not be in the function that was running when the exception occurred. In some cases it may be in a function much higher on the stack. The currently running function, as well as all functions on the stack frame, are terminated. During this process, the stack is “unwound”: local variables of terminated functions, unless they are static, are cleared from the stack.

As it unwinds the stack, the operating system calls any termination handlers you’ve written for each function. Use of a termination handler gives you a chance to clean up resources that otherwise would remain open due to abnormal termination. If you’ve entered a critical section, you can exit in the termination handler. If the program is going to shut down, you can perform other housekeeping tasks such as closing and removing temporary files.


Writing an Exception Handler

Home | Overview | How Do I | FAQ

Exception handlers are typically used to respond to specific errors. You can use the exception-handling syntax to filter out all exceptions other than those you know how to handle. Other exceptions should be passed to other handlers (possibly in the run-time library or the operating system) written to look for those specific exceptions.

What do you want to know more about?

  • Syntax of exception handlers

  • Writing an exception filter

  • Raising software exceptions

  • Hardware exceptions

  • Restrictions on exception handlers


Syntax of Exception Handlers

Home | Overview | How Do I | FAQ

The structure for C exception handlers is:

__try {

statement-block-1
}
__except ( filter ) {
statement-block-2
}

The statements in statement-block-1 are executed unconditionally. During execution of statement-block-1, the exception handler defined by filter and statement-block-2 is active (it becomes the current exception handler).

If an exception occurs during execution of statement-block-1, including any function called directly or indirectly, the system gives control to the current exception handler — unless a handler with higher precedence takes control.

For example, in the following code, the first exception is handled by the outer block, because it is outside the scope of the inner __try block. The second exception is handled by the inner block, which takes precedence.

__try {
    float x, y=0;
    x = 5 / y;        // This exception handled by outer block
    __try {
        x = 0;
        y = 27 / x;   // This exception handled by inner block
    }
    __except( GetExceptionCode() == STATUS_FLOATING_DIVIDE_BY_ZERO) {
        printf("handled by inner block");
    }
}
__except( GetExceptionCode() == STATUS_FLOATING_DIVIDE_BY_ZERO ) {
    printf( "handled by outer block" );
}

This code shows an example of nested exception handlers. Note that calling a function that has a try-except block has the same effect as nesting; the try-except block in the most recently called function takes precedence.

When an exception handler takes control, the system first evaluates the filter. One of the powerful features of structured exception handling is that although filter is evaluated out of normal program sequence (often during execution of another function), filter can refer to local variables within its scope just as any C expression. After filter is evaluated, the next action depends on the value returned.

Value of filter | Description
EXCEPTION_CONTINUE_SEARCH (0) | Passes control to exception handler with next highest precedence. The handler has declined to recognize the exception.
EXCEPTION_CONTINUE_EXECUTION( –1) | Dismisses exception, and continues execution at the location where the exception was raised.
EXCEPTION_EXECUTE_HANDLER (1) | Handles exception by executing statements in statement-block-2. Execution then falls through to the end of this statement block.

If the value of filter is EXCEPTION_EXECUTE_HANDLER, execution does not resume where the exception was raised, but falls through to the end of statement-block-2 after it is executed. All blocks and function calls nested inside statement-block-1 are terminated before statement-block-2 is entered.


Writing an Exception Filter

Home | Overview | How Do I | FAQ

You can handle an exception either by jumping to the level of the exception handler or by continuing execution. Instead of using statement-block-2 to handle the exception and falling through, you can use filter to clean up the problem and then, by returning –1, resume normal flow without clearing the stack.

Note Some exceptions cannot be continued. If filter evaluates to –1 for such an exception, the system raises a new exception. When you call RaiseException, you determine whether the exception will continue.

For example, the following code uses a function call in the filter expression: this function handles the problem and then returns –1 to resume normal flow of control:

main ()
{
    int Eval_Exception( void );

    __try {
    ...
    }
    __except ( Eval_Exception( GetExceptionCode( ))) {
       // No code; this block never executed.
}
...
}

int Eval_Exception ( int n_except )
{
    if ( n_except != STATUS_INTEGER_OVERFLOW &&
        n_except != STATUS_FLOATING_OVERFLOW )    // Pass on most
        return EXCEPTION_CONTINUE_SEARCH;            //  exceptions

    // Execute some code to clean up problem

    ResetVars( 0 );      // ResetVars -- example function to initialize
                      //  data to 0
    return EXCEPTION_CONTINUE_EXECUTION;
}

It is a good idea to use a function call in the filter expression whenever filter needs to do anything complex. Evaluating the expression causes execution of the function, in this case, Eval_Exception.

Note the use of GetExceptionCode to determine the exception. You must call this function inside the filter itself. Eval_Exception cannot call GetExceptionCode, but it must have the exception code passed to it.

This handler passes control to another handler unless the exception is an integer or floating-point overflow. If it is, the handler calls a function (ResetVars is only an example, not an API function) to reset some global variables. Statement-block-2, which in this example is empty, can never be executed because Eval_Exception never returns EXCEPTION_EXECUTE_HANDLER (1).

Using a function call is a good general-purpose technique for dealing with complex filter expressions. Two other C language features that are useful are:

  • The conditional operator

  • The comma operator

The conditional operator is frequently useful, because it can be used to check for a specific return code and then return one of two different values. For example, the filter in the following code recognizes the exception only if the exception is STATUS_INTEGER_OVERFLOW:

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ? 1 : 0 ) {

The purpose of the conditional operator in this case is mainly to provide clarity, because the following code produces the same results:

__except( GetExceptionCode() == STATUS_INTEGER_OVERFLOW ) {

The conditional operator is more useful in situations where you might want the filter to evaluate to –1, EXCEPTION_CONTINUE_EXECUTION.

The comma operator enables you to perform multiple, independent operations inside a single expression. The effect is roughly that of executing multiple statements and then returning the value of the last expression. For example, the following code stores the exception code in a variable and then tests it:

__except( nCode = GetExceptionCode(), nCode == STATUS_INTEGER_OVERFLOW )


Raising Software Exceptions

Home | Overview | How Do I | FAQ

Some of the most common sources of program errors are not flagged as exceptions by the system. For example, if you attempt to allocate a memory block but there is insufficient memory, the run-time or API function does not raise an exception but returns an error code.

However, you can treat any condition as an exception by detecting that condition in your code and then reporting it by calling the RaiseException function. By flagging errors this way, you can bring the advantages of structured exception handling to any kind of run-time error.

To use structured exception handling with errors:

  • Define your own exception code for the event.

  • Call RaiseException when you detect a problem.

  • Use exception-handling filters to test for the exception code you defined.

The WINERROR.H file shows the format for exception codes. To make sure that you do not define a code that conflicts with an existing exception code, set the third most significant bit to 1. The four most-significant bits should be set as shown in the following table.

Bits | Recommended binary setting | Description
31-30 | 11 | These two bits describe the basic status of the code: 11 = error, 00 = success, 01 = informational, 10 = warning.
29 | 1 | Client bit. Set to 1 for user-defined codes.
28 | 0 | Reserved bit. (Leave set to 0.)

You can set the first two bits to a setting other than 11 binary if you want, although the “error” setting is appropriate for most exceptions. The important thing to remember is to set bits 29 and 28 as shown in the previous table.

The resulting error code should therefore have the highest four bits set to hexadecimal E. For example, the following definitions define exception codes that do not conflict with any Windows 95 or Windows NT exception codes. (You may, however, need to check which codes are used by third-party DLLs.)

#define STATUS_INSUFFICIENT_MEM       0xE0000001
#define STATUS_FILE_BAD_FORMAT        0xE0000002

After you have defined an exception code, you can use it to raise an exception. For example, the following code raises the STATUS_INSUFFICIENT_MEM exception in response to a memory allocation problem:

lpstr = _malloc( nBufferSize );
if (lpstr == NULL)
    RaiseException( STATUS_INSUFFICIENT_MEM, 0, 0, 0);

If you want to simply raise an exception, you can set the last three parameters to 0. The three last parameters are useful for passing additional information and setting a flag that prevents handlers from continuing execution. See the RaiseException function in the Win32 Programmer’s Reference for more information.

In your exception-handling filters, you can then test for the codes you’ve defined. For example:

__try {
    ...
}
__except (GetExceptionCode() == STATUS_INSUFFICIENT_MEM ||
        GetExceptionCode() == STATUS_FILE_BAD_FORMAT )


Hardware Exceptions

Home | Overview | How Do I | FAQ

Most of the standard exceptions recognized by the operating system are hardware-defined exceptions. Windows 95 and Windows NT recognize a few low-level software exceptions, but these are usually best handled by the operating system.

Windows NT maps the hardware errors of different processors to the exception codes in this section. In some cases, a processor may generate only a subset of these exceptions. Windows NT preprocesses information about the exception and issues the appropriate exception code.

The hardware exceptions recognized by Windows NT are summarized in the following table:

Exception code | Cause of exception
STATUS_ACCESS_VIOLATION | Reading or writing to an inaccessible memory location.
STATUS_BREAKPOINT | Encountering a hardware-defined breakpoint; used only by debuggers.
STATUS_DATATYPE_MISALIGNMENT | Reading or writing to data at an address that is not properly aligned; for example, 16-bit entities must be aligned on 2-byte boundaries. (Not applicable to Intel 80x86 processors.)
STATUS_FLOATING_DIVIDE_BY_ZERO | Dividing floating-point type by 0.0.
STATUS_FLOATING_OVERFLOW | Exceeding maximum positive exponent of floating-point type.
STATUS_FLOATING_UNDERFLOW | Exceeding magnitude of lowest negative exponent of floating-point type.
STATUS_FLOATING_RESEVERED_OPERAND | Using a reserved floating-point format (invalid use of format).
STATUS_ILLEGAL_INSTRUCTION | Attempting to execute an instruction code not defined by the processor.
STATUS_PRIVILEGED_INSTRUCTION | Executing an instruction not allowed in current machine mode.
STATUS_INTEGER_DIVIDE_BY_ZERO | Dividing an integer type by 0.
STATUS_INTEGER_OVERFLOW | Attempting an operation that exceeds the range of the integer.
STATUS_SINGLE_STEP | Executing one instruction in single-step mode; used only by debuggers.

Many of the exceptions listed in the previous table are intended to be handled by debuggers, the operating system, or other low-level code. With the exception of integer and floating-point errors, your code should not handle these errors. Thus, you should usually use the exception-handling filter to ignore exceptions (evaluate to 0). Otherwise, you may prevent lower-level mechanisms from responding appropriately. You can, however, take appropriate precautions against the potential effect of these low-level errors by writing termination handlers.


Restrictions on Exception Handlers

Home | Overview | How Do I | FAQ

The principal limitation to using exception handlers in code is that you cannot use a goto statement to jump into a __try statement block. Instead, you must enter the statement block through normal flow of control. You can jump out of a __try statement block and nest exception handlers as you choose.


Writing a Termination Handler

Home | Overview | How Do I | FAQ

Unlike an exception handler, a termination handler is always executed, regardless of whether the protected block of code terminated normally. The sole purpose of the termination handler should be to ensure that resources, such as memory, handles, and files, are properly closed regardless of how a section of code finishes executing.

What do you want to know more about?

  • Syntax of termination handlers

  • Cleaning up resources

  • Timing of actions in exception handling

  • Restrictions on termination handlers


Syntax of Termination Handlers

Home | Overview | How Do I | FAQ

The structure of a termination handler is:

__try {

statement-block-1
}
__finally {
statement-block-2

}

The statements in statement-block-1 are executed unconditionally. The statements in statement-block-2 are always executed, in one of two ways:

  • If statement-block-1 finishes execution normally, statement-block-2 is then executed.

  • If statement-block-1 is prematurely terminated for any reason, including a jump out of the block, the system executes statement-block-2 as a part of the process of unwinding the stack.

In the second case, the AbnormalTermination function returns TRUE if called from within statement-block-2; otherwise, it returns FALSE.

If statement-block-1 was abnormally terminated, the termination handler is executed as a part of the process of unwinding the stack. If control jumps outside of several blocks of code at once, the system clears the stack frame for each block of code or function exited, starting with the lowest (most deeply-nested) stack frame. As each frame is cleared, the system executes its termination handler.

For example, suppose a series of function calls links function A to function D, as shown in the following figure. Each function has one termination handler. If an exception is raised in function D and handled in A, the termination handlers are called in this order as the system unwinds the stack: D, C, B.

Order of Termination-Handler Execution


Cleaning up Resources

Home | Overview | How Do I | FAQ

During termination-handler execution, you may not know which resources are actually allocated before the termination handler was called. It is possible that the __try statement block was interrupted before all resources were allocated, so that not all resources were opened.

Therefore, to be safe, you should check to see which resources are actually open before proceeding with termination-handling cleanup. A recommended procedure is to:

  1. Initialize handles to NULL.

  2. In the __try statement block, allocate resources. Handles are set to positive values as the resource is allocated.

  3. In the __finally statement block, release each resource whose corresponding handle or flag variable is nonzero or not NULL.

For example, the following code uses a termination handler to close three files and a memory block that were allocated in the __try statement block. Before cleaning up a resource, the code first checks to see if the resource was allocated.

void    FileOps()
{
   FILE *fp1, *fp2, *fp3;
    LPVOID  lpvoid;

    lpvoid = fp1 = fp2 = fp3 = NULL;
    __try {
        lpvoid = malloc( BUFFERSIZE );
        fp1 = fopen( "ADDRESS.DAT", "w+" );
        fp2 = fopen( "NAMES.DAT", "w+" );
        fp3 = fopen( "CARS.DAT", "w+" );
        .
        .
        .
    }
    __finally {
        if ( fp1 ) fclose( fp1 );
        if ( fp2 ) fclose( fp2 );
        if ( fp3 ) fclose( fp3 );
        if ( lpvoid ) free( lpvoid );
    }
}


Timing of Exception Handling: A Summary

Home | Overview | How Do I | FAQ

A termination handler is executed no matter how the __try statement block is terminated. Causes include jumping out of the __try block, a longjmp statement that transfers control out of the block, and unwinding the stack due to exception handling.

Note Visual C++ supports two forms of the setjmp and longjmp statements. The fast version bypasses termination handling but is more efficient. To use this version, include the file SETJMP.H. The other version supports termination handling as described in the previous paragraph. To use this version, include the file SETJMPEX.H. The increase in performance of the fast version depends on hardware configuration.

The operating system executes all termination handlers in the proper order before any other code can be executed, including the body of an exception handler.

When the cause for interruption is an exception, the system must first execute the filter portion of one or more exception handlers before deciding what to terminate. The order of events is:

  1. An exception is raised.

  2. The system looks at the hierarchy of active exception handlers and executes the filter of the handler with highest precedence; this is the exception handler most recently installed and most deeply nested, in terms of blocks and function calls.

  3. If this filter passes control (returns 0), the process continues until a filter is found that does not pass control.

  4. If this filter returns –1, execution continues where the exception was raised, and no termination takes place.

  5. If the filter returns 1, the following events occur:
    • The system unwinds the stack, clearing all stack frames between the currently executing code (where the exception was raised) and the stack frame that contains the exception handler gaining control.

    • As the stack is unwound, each termination handler on the stack is executed.

    • The exception handler itself is executed.

    • Control passes to the line of code after the end of this exception handler.


Restrictions on Termination Handlers

Home | Overview | How Do I | FAQ

You cannot use a goto statement to jump into a __try statement block or a __finally statement block. Instead, you must enter the statement block through normal flow of control. (You can, however, jump out of a __try statement block.) Also, you cannot nest an exception handler or termination handler inside a __finally block.

In addition, some kinds of code permitted in a termination handler produce questionable results, so you should use them with caution, if at all. One is a goto statement that jumps out of a __finally statement block. If the block is executing as part of normal termination, nothing unusual happens. But if the system is unwinding the stack, that unwinding stops, and the current function gains control as if there were no abnormal termination.

A return statement inside a __finally statement block presents roughly the same situation. Control returns to the immediate caller of the function containing the termination handler. If the system was unwinding the stack, this process is halted, and the program proceeds as if there had been no exception raised.


Using Structured Exception Handling with C++

Home | Overview | How Do I | FAQ

Structured exception handling described in these articles works with both C and C++ source files. However, it is not specifically designed for C++ and is not recommended. You can ensure that your code is more portable by using C++ exception handling. Also, the C++ exception handling mechanism is more flexible, in that it can handle exceptions of any type.

Microsoft C++ now supports the C++ exception handling model, based on the ISO WG21/ANSI X3J16 working papers towards the evolving standard for C++. This mechanism automatically handles destruction of local objects during stack unwind. If you are writing fault-tolerant C++ code, and you want to implement exception handling, it is strongly recommended that you use C++ exception handling, rather than structured exception handling. (Note that while the C++ compiler supports structured exception handling constructs as described in these articles, the standard C compiler does not support the C++ exception handling syntax.) For detailed information about C++ exception handling, see Exception Handling Topics (C++) and the Annotated C++ Reference Manual by Margaret Ellis and Bjarne Stroustrup.


Files Topics

Home | Overview | How Do I

File-handling classes and functions are available from MFC, the run-time library, and Win32. For details about these alternatives, see the overview.

The articles in this family focus on MFC file-handling mechanisms via class CFile.

What do you want to know more about?

  • Class CFile

  • MFC’s serialization mechanism

  • MFC classes derived from CFile

  • Opening files

  • Reading and writing files

  • Closing files

  • Accessing file status


Files in MFC

Home | Overview | How Do I

In the Microsoft Foundation Class Library (MFC), class CFile handles normal file I/O operations. This family of articles explains how to open and close files as well as read and write data to those files. It also discusses file status operations. For a description of how to use the object-based serialization features of MFC as an alternative way of reading and writing data in files, see the article Serialization (Object Persistence).

Note When you use MFC CDocument objects, the framework does much of the serialization work for you. In particular, the framework creates and uses the CFile object. You only have to write code in your override of the Serialize member function of class CDocument.

The CFile class provides an interface for general-purpose binary file operations. The CStdioFile and CMemFile classes derived from CFile and the CSharedFile class derived from CMemFile supply more specialized file services.

What do you want to know more about?

  • Opening files

  • Reading and writing files

  • Closing files

  • Accessing file status


Opening Files

Home | Overview | How Do I

In MFC, the most common way to open a file is a two-stage process.

To open a file

  1. Create the file object without specifying a path or permission flags.

    You usually create a file object by declaring a CFile variable on the stack frame.

  2. Call the Open member function for the file object, supplying a path and permission flags.

    The return value for Open will be nonzero if the file was opened successfully or 0 if the specified file could not be opened. The Open member function is prototyped as follows:

    virtual BOOL Open( LPCTSTR lpszFileName, UINT nOpenFlags, CFileException* pError = NULL );

    The open flags specify which permissions, such as read-only, you want for the file. The possible flag values are defined as enumerated constants within the CFile class, so they are qualified with “CFile::,” as in CFile::modeRead. Use the CFile::modeCreate flag if you want to create the file.

The following example shows how to create a new file with read/write permission (replacing any previous file with the same path):

char* pszFileName = "c:\\test\\myfile.dat";
CFile myFile;
CFileException fileException;

if ( !myFile.Open( pszFileName, CFile::modeCreate |
          CFile::modeReadWrite ), &fileException )
{
    TRACE( "Can't open file %s, error = %u\n",
       pszFileName, fileException.m_cause );
}

Note This example creates and opens a file. If there are problems, the Open call can return a CFileException object in its last parameter, as shown here. The TRACE macro prints both the file name and a code indicating the reason for failure. You can call the AfxThrowFileException function if you require more detailed error reporting.


Reading and Writing Files

Home | Overview | How Do I

If you’ve used the C run-time library file-handling functions, MFC reading and writing operations will appear familiar. This article describes reading directly from and writing directly to a CFile object. You can also do buffered file I/O with the CArchive class.

To read from and write to the file

  • Use the Read and Write member functions to read and write data in the file.

    -or-

  • The Seek member function is also available for moving to a specific offset within the file.

Read takes a pointer to a buffer and the number of bytes to read and returns the actual number of bytes that were read. If the required number of bytes could not be read because end-of-file (EOF) is reached, the actual number of bytes read is returned. If any read error occurs, an exception is thrown. Write is similar to Read, but the number of bytes written is not returned. If a write error occurs, including not writing all the bytes specified, an exception is thrown. If you have a valid CFile object, you can read from it or write to it as shown in the following example:

char      szBuffer[256];
UINT      nActual = 0;
CFile myFile;

myFile.Write( szBuffer, sizeof( szBuffer ) );
myFile.Seek( 0, CFile::begin );
nActual = myFile.Read( szBuffer, sizeof( szBuffer ) );

Note You should normally carry out input/output operations within a try/catch exception handling block. For more information, see Exception Handling Syntax.


Closing Files

Home | Overview | How Do I

As usual in I/O operations, once you finish with a file, you must close it.

To close a file

  • Use the Close member function. This function closes the file-system file and flushes buffers if necessary.

If you allocated the CFile object on the frame (as in the examples shown earlier), the object will automatically be closed and then destroyed when it goes out of scope. Note that deleting the CFile object does not delete the physical file in the file system.


Accessing File Status

Home | Overview | How Do I

CFile also supports getting file status, including whether the file exists, creation and modification dates and times, logical size, and path.

To get file status

  • Use the CFile class to get and set information about a file. One useful application is to use the CFile static member function GetStatus to determine if a file exists. GetStatus returns 0 if the specified file does not exist.

Thus, you could use the result of GetStatus to determine whether to use the CFile::modeCreate flag when opening a file, as shown by the following example:

CFile theFile;
char* szFileName = "c:\\test\\myfile.dat";
BOOL bOpenOK;

CFileStatus status;
if( CFile::GetStatus( szFileName, status ) )
{
    // Open the file without the Create flag
    bOpenOK = theFile.Open( szFileName,
                    CFile::modeWrite );
}
else
{
    // Open the file with the Create flag
    bOpenOK = theFile.Open( szFileName,
                    CFile::modeCreate | CFile::modeWrite );
}

For related information, see Serialization (Object Persistence).


International Programming Topics

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

An important aspect of developing applications for international markets is the adequate representation of local character sets. The ASCII character set defines characters in the range 0x00 to 0x7F. There are other character sets, primarily European, that define the characters within the range 0x00 to 0x7F identically to the ASCII character set and also define an extended character set from 0x80 to 0xFF. Thus, an 8-bit, single-byte-character set (SBCS) is sufficient to represent the ASCII character set, as well as the character sets for many European languages. However, some non-European character sets, such as Japanese Kanji, include many more characters than can be represented in a single-byte coding scheme, and therefore require multibyte-character set (MBCS) encoding.

This family of articles describes the Visual C++ support for extended character sets, and focuses on writing portable code that can be built for several different character sets.

What do you want to know more about?

  • Unicode and MBCS programming in Visual C++

  • Support for Unicode in Visual C++

  • Support for Multibyte Character Sets (MBCS) in Visual C++

  • Generic-Text Mappings in TCHAR.H


Unicode and MBCS

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

The Microsoft Foundation Class Library (MFC), the C run-time library for Visual C++, and the Visual C++ development environment are enabled to assist your international programming. They provide:

  • Support for the Unicode standard on Windows NT.

    Unicode is a 16-bit character encoding, providing enough encodings for all languages. All ASCII characters are included in Unicode as “widened” characters.

    Note The Unicode standard is not supported on Windows 95.

  • Support for a form of Multibyte Character Set (MBCS) called Double Byte Character Set (DBCS) on all platforms.

    DBCS characters are composed of one or two bytes. Some ranges of bytes are set aside for use as “lead bytes.” A lead byte specifies that it and the following “trail byte” comprise a single two-byte-wide character. You must keep track of which bytes are lead bytes. In a particular multibyte-character set, the lead bytes fall within a certain range, as do the trail bytes. When these ranges overlap, it may be necessary to evaluate the context to determine whether a given byte is functioning as a lead byte or a trail byte.

  • Support for tools that simplify MBCS programming of applications written for international markets.

    When run on an MBCS-enabled version of the Windows NT operating system, the Visual C++ development system — including the integrated source code editor, debugger, and command line tools — is completely MBCS-enabled. For more information, see MBCS Support in Visual C++.

Note In this documentation, “MBCS” is used to describe all non-Unicode support for wide characters. In Visual C++, MBCS always means DBCS. Character sets wider than two bytes are not supported.

By definition, the ASCII character set is a subset of all multibyte-character sets. In many multibyte character sets, each character in the range 0x00 – 0x7F is identical to the character that has the same value in the ASCII character set. For example, in both ASCII and MBCS character strings, the one-byte NULL character ('\0') has value 0x00 and indicates the terminating null character.

See Also International Enabling


International Enabling

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Most traditional C and C++ code makes assumptions about character and string manipulation that do not work well for international applications. While both MFC and the run-time library support Unicode or MBCS, there is still work for you to do. To guide you, this section explains the meaning of “international enabling” in Visual C++:

  • Both Unicode and MBCS are enabled by means of portable data types in MFC function parameter lists and return types. These types are conditionally defined in the appropriate ways, depending on whether your build defines the symbol _UNICODE or the symbol _MBCS (which means DBCS). Different variants of the MFC libraries are automatically linked with your application, depending on which of these two symbols your build defines.

  • Class library code uses portable run-time functions and other means to ensure correct Unicode or MBCS behavior.

  • You still must handle certain kinds of internationalization tasks in your code:
    • Use the same portable run-time functions that make MFC portable under either environment.

    • Make literal strings and characters portable under either environment, using the _T macro. For more information, see Generic-Text Mappings in TCHAR.H.

    • Take precautions when parsing strings under MBCS. These precautions are not needed under Unicode. For more information, see MBCS Programming Tips.

    • Take care if you mix ANSI (8-bit) and Unicode (16-bit) characters in your application. It’s possible to use ANSI characters in some parts of your program and Unicode characters in others, but you cannot mix them in the same string.

    • Don’t “hard-code” strings in your application. Instead, make them STRINGTABLE resources by adding them to the application’s .rc file. Your application can then be localized without requiring source code changes or recompilation. For more information on STRINGTABLE resources, see the String Editor documentation in Visual C++ User’s Guide.

Note European and MBCS character sets have some characters, such as accented letters, with character codes greater than 0x80. Since most code uses signed characters, these characters greater than 0x80 are sign-extended when converted to int. This is a problem for array indexing because the sign-extended characters, being negative, will index outside the array.

Languages that use MBCS, such as Japanese, are also unique. Since a character may consist of one or two bytes, you should always manipulate both bytes at the same time.

See Also Internationalization Strategies


Internationalization Strategies

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Depending on your target operating system(s) and markets, you have several internationalization strategies:

  • Your application uses Unicode and therefore runs on Windows NT (but not on Windows 95).

    You use Unicode-specific programming techniques and all characters are 16 bits wide (although you can use ANSI characters in some parts of your program for special purposes). The C run-time library provides functions, macros, and data types for Unicode-only programming. MFC is fully Unicode-enabled.

  • Your application uses MBCS and can be run on any Win32 platform.

    You use MBCS-specific programming techniques. Strings can contain single-byte characters, double-byte characters, or both. The C run-time library provides functions, macros, and data types for MBCS-only programming. MFC is fully MBCS-enabled.

  • The source code for your application is written for complete portability — by recompiling with the symbol _UNICODE or the symbol _MBCS defined, you can produce versions that use either. For more information, see Generic-Text Mappings in TCHAR.H.

    You use fully portable C run-time functions, macros, and data types. MFC’s flexibility supports any of these strategies.

The remainder of this family of articles focuses on writing completely portable code that you can build as Unicode or as MBCS.

See Also Locales and Code Pages


Locales and Code Pages

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

A “locale” reflects the local conventions and language for a particular geographical region. A given language may be spoken in more than one country; for example, Portuguese is spoken in Brazil as well as in Portugal. Conversely, a country may have more than one official language. For example, Canada has two: English and French. Thus, Canada has two distinct locales: Canadian-English and Canadian-French. Some locale-dependent categories include the formatting of dates and the display format for monetary values.

The language determines the text and data formatting conventions, while the country determines the national conventions. Every language has a unique mapping, represented by “code pages,” which includes characters other than those in the alphabet (such as punctuation marks and numbers). A code page is a character set and is related to the current locale and language. As such, a locale is a unique combination of language, country, and code page. The code page setting can determine the locale setting and can be changed at run time by calling the setlocale function.

Different languages may use different code pages. For example, the ANSI code page 1252 is used for American English and most European languages, and the ANSI code page 932 is used for Japanese Kanji. Virtually all code pages share the ASCII character set for the lowest 128 characters (0x00 to 0x7F).

Any single-byte code page can be represented in a table (with 256 entries) as a mapping of byte values to characters (including numbers and punctuation marks), or glyphs. Any multibyte code page can also be represented as a very large table (with 64K entries) of double-byte values to characters. In practice, however, it are usually represented as a table for the first 256 (single-byte) characters and as ranges for the double-byte values.

The C run-time library has two types of internal code pages: locale and multibyte. You can change the current code page during program execution (see the documentation for the setlocale and _setmbcp functions). Also, the run-time library may obtain and use the value of the operating system code page. In Windows NT, the operating system code page is the “system default ANSI” code page. This code page is constant for the duration of the program’s execution.

When the locale code page changes, the behavior of the locale-dependent set of functions changes to that dictated by the chosen code page. By default, all locale-dependent functions begin execution with a locale code page unique to the “C” locale. You can change the internal locale code page (as well as other locale-specific properties) by calling the setlocale function. A call to setlocale(LC_ALL, "") will set the locale to that indicated by the operating system’s default code page.

Similarly, when the multibyte code page changes, the behavior of the multibyte functions changes to that dictated by the chosen code page. By default, all multibyte functions begin execution with a multibyte code page corresponding to the operating system’s default code page. You can change the internal multibyte code page by calling the _setmbcp function.

The C run-time function setlocale sets, changes, or queries some or all of the current program’s locale information. The _wsetlocale routine is a wide-character version of setlocale; the arguments and return values of _wsetlocale are wide-character strings.

See Also Benefits of Character Set Portability


Benefits of Character Set Portability

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

You can benefit from using MFC and C run-time portability features even if you don’t currently intend to internationalize your application:

  • Coding portably makes your code base flexible. You can later move it easily to Unicode or MBCS.

  • Using Unicode makes your applications for Windows NT more efficient. Windows NT uses Unicode, so non-Unicode strings passed to and from the operating system must be translated, incurring overhead.

  • Using MBCS enables you to support international markets on Win32 platforms other than Windows NT, such as Windows 95.

See Also Support for Unicode


Support for Unicode

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

A “wide character” is a two-byte multilingual character code. Any character used in modern computing worldwide, including technical symbols and special publishing characters, can be represented according to the Unicode specification as a wide character. Because each wide character is always represented in a fixed size of 16 bits, using wide characters simplifies programming with international character sets.

A wide-character string is represented as a wchar_t[] array and is pointed to by a wchar_t* pointer. Any ASCII character can be represented as a wide character by prefixing the letter L to the character. For example, L'\0' is the terminating wide (16-bit) NULL character. Similarly, any ASCII string literal can be represented as a wide-character string literal by prefixing the letter L to the ASCII literal (L"Hello").

Generally, wide characters take more space in memory than multibyte characters but are faster to process. In addition, only one locale can be represented at a time in multibyte encoding, whereas all character sets in the world are represented simultaneously by the Unicode representation.

The MFC framework is Unicode-enabled throughout, except for the database classes. (ODBC is not Unicode-enabled.) MFC accomplishes Unicode enabling by using “portable” macros throughout, as shown in the following table:

Portable Data Types in MFC

Non-portable data type(s) | Replaced by this macro
char | _TCHAR
char*, LPSTR (Win32 data type) | LPTSTR
const char*, LPCSTR (Win32 data type) | LPCTSTR

Class CString uses _TCHAR as its base and provides constructors and operators for easy conversions. Most string operations for Unicode can be written by using the same logic used for handling the Windows ANSI character set, except that the basic unit of operation is a 16-bit character instead of an 8-bit byte. Unlike working with multibyte character sets (MBCS), you do not have to (and should not) treat a Unicode character as if it were two distinct bytes.

See Also Support for Using wmain


Support for Using wmain

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Microsoft Specific —>

Visual C++ supports defining a wmain function and passing wide-character arguments to your Unicode application. You declare formal parameters to wmain, using a format similar to main. You can then pass wide-character arguments and, optionally, a wide-character environment pointer to the program. The argv and envp parameters to wmain are of type wchar_t*. For example:

wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )

Note MFC Unicode applications use wWinMain as the entry point. In this case, CWinApp::m_lpCmdLine is a Unicode string. Be sure to set wWinMainCRTStartup as the Entry Point symbol in the Output category of the Link tab in the Project Settings dialog box.

If your program uses a main function, the multibyte-character environment is created by the run-time library at program startup. A wide-character copy of the environment is created only when needed (for example, by a call to the _wgetenv or _wputenv functions). On the first call to _wputenv, or on the first call to _wgetenv if an MBCS environment already exists, a corresponding wide-character string environment is created. The environment is then pointed to by the _wenviron global variable, which is a wide-character version of the _environ global variable. At this point, two copies of the environment (MBCS and Unicode) exist simultaneously and are maintained by the run-time system throughout the life of the program.

Similarly, if your program uses a wmain function, a wide-character environment is created at program startup and is pointed to by the _wenviron global variable. An MBCS (ASCII) environment is created on the first call to _putenv or getenv, and is pointed to by the _environ global variable.

END Microsoft Specific

See Also Unicode Programming Summary


Unicode Programming Summary

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

To take advantage of the MFC and C run-time support for Unicode, you need to:

  • Define _UNICODE.

    Define the symbol _UNICODE before you build your program.

  • Specify entry point.

    In the Output category of the Link tab in the Project Settings dialog box, set the Entry Point Symbol to wWinMainCRTStartup.

  • Use “portable” run-time functions and types.

    Use the proper C run-time functions for Unicode string handling. You can use the wcs family of functions, but you may prefer the fully “portable” (internationally enabled) _TCHAR macros. These macros are all prefixed with _tcs; they substitute, one for one, for the str family of functions. These functions are described in detail in the Internationalization section of the Run-Time Library Reference. For more information, see Generic-Text Mappings in TCHAR.H.

    Use _TCHAR and the related portable data types described in Support for Unicode.

  • Handle literal strings properly.

    The Visual C++ compiler interprets a literal string coded as

    L"this is a literal string"

    to mean a string of Unicode characters. You can use the same prefix for literal characters. Use the _T macro to code literal strings generically, so they compile as Unicode strings under Unicode or as ANSI strings (including MBCS) without Unicode. For example, instead of:

    pWnd->SetWindowText( “Hello” );

    use:

    pWnd->SetWindowText( _T(“Hello”) );

    With _UNICODE defined, _T translates the literal string to the L-prefixed form; otherwise, _T translates the string without the L prefix.

    Tip The _T macro is identical to the _TEXT macro.

  • Be careful passing string lengths to functions.

    Some functions want the number of characters in a string; others want the number of bytes. For example, if _UNICODE is defined, the following call to a CArchive object will not work (str is a CString):

    archive.Write( str, str.GetLength( ) );    // invalid

    In a Unicode application, the length gives you the number of characters but not the correct number of bytes, since each character is two bytes wide. Instead, you must use:

    archive.Write( str, str.GetLength( ) * sizeof( _TCHAR ) );    // valid

    which specifies the correct number of bytes to write.

    However, MFC member functions that are character-oriented, rather than byte-oriented, work without this extra coding:

    pDC->TextOut( str, str.GetLength( ) );

    CDC::TextOut takes a number of characters, not a number of bytes.

To summarize, MFC and the run-time library provide the following support for Unicode programming under Windows NT:

  • Except for database class member functions, all MFC functions are Unicode-enabled, including CString. CString also provides Unicode/ANSI conversion functions.

  • The run-time library supplies Unicode versions of all string-handling functions. (The run-time library also supplies “portable” versions suitable for Unicode or for MBCS. These are the _tcs macros.)

  • TCHAR.H supplies portable data types and the _T macro for translating literal strings and characters. See Generic-Text Mappings in TCHAR.H.

  • The run-time library provides a wide-character version of main. Use wmain to make your application “Unicode-aware.”


Support for Multibyte Character Sets (MBCS)

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

For platforms used in markets whose languages use large character sets, the best alternative to Unicode is MBCS. MFC supports MBCS by using “internationalizable” data types and C run-time functions. You should do the same in your code.

Under MBCS, characters are encoded in either one or two bytes. In two-byte characters, the first, or “lead-byte,” signals that both it and the following byte are to be interpreted as one character. The first byte comes from a range of codes reserved for use as lead bytes. Which ranges of bytes can be lead bytes depends on the code page in use. For example, Japanese code page 932 uses the range 0x81 through 0x9F as lead bytes, but Korean code page 949 uses a different range.

Consider all of the following in your MBCS programming:

MBCS characters in the environment

MBCS characters can appear in strings such as file and directory names.

Editing operations

Editing operations in MBCS applications should operate on characters, not bytes. The caret should not split a character, the RIGHT ARROW key should move right one character, and so on. Delete should delete a character; Undo should reinsert it.

String handling

In an application that uses MBCS, string handling poses special problems. Characters of both widths are mixed in a single string; therefore you must remember to check for lead bytes.

Run-time library support

The C run-time library and MFC support single-byte, MBCS, and Unicode programming. Single-byte strings are processed with the str family of run-time functions, MBCS strings are processed with corresponding _mbs functions, and Unicode strings are processed with corresponding wcs functions. MFC class member function implementations use portable run-time functions that map, under the right circumstances, to the normal str family of functions, the MBCS functions, or the Unicode functions, as described in “MBCS/Unicode portability.”

MBCS/Unicode portability

Using the header file TCHAR.H, you can build single-byte, MBCS, and Unicode applications from the same sources. TCHAR.H defines macros prefixed with _tcs , which map to str, _mbs, or wcs functions, as appropriate. To build MBCS, define the symbol _MBCS. To build Unicode, define the symbol _UNICODE. By default, _MBCS is defined for MFC applications. For more information, see Generic-Text Mappings in TCHAR.H.

Note Behavior is undefined if you define both _UNICODE and _MBCS.

The MBCTYPE.H and MBSTRING.H header files define MBCS-specific functions and macros, which you may need in some cases. For example, _ismbblead tells you whether a specific byte in a string is a lead byte.

See Also MBCS Support in Visual C++


MBCS Support in Visual C++

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

When run on an MBCS-enabled version of the Windows 95 or Windows NT operating system, the Visual C++ development system, including the integrated source code editor, debugger, and command line tools, is completely MBCS-enabled. Visual C++ will accept double-byte characters wherever it is appropriate to do so. This includes path names and file names in dialog boxes, and text entries in the Visual C++ resource editor (for example, static text in the dialog editor and static text entries in the icon editor). In addition, the preprocessor recognizes some double-byte directives ? for example, file names in #include statements, and as arguments to the code_seg and data_seg pragmas. In the source code editor, double-byte characters in comments and string literals are accepted, although not in C/C++ language elements (such as variable names).

Support for the Input Method Editor (IME)

Applications written for Far East markets that use MBCS (for example, Japan) normally support the Windows IME for entering both single- and double-byte characters. The Visual C++ development environment contains full support for the IME.

Japanese keyboards do not directly support Kanji characters. The IME converts a phonetic string, entered in one of the other Japanese alphabets, Romaji, Katakana, or Hiragana, into its possible Kanji representations. If there is ambiguity, you can select from several alternatives. Once you have selected the intended Kanji character, the IME passes two WM_CHAR messages to the controlling application.

The IME, activated by the ALT+` key combination, appears as a set of buttons (an indicator) and a conversion window. The application positions the window at the text insertion point. The application must handle WM_MOVE and WM_SIZE messages by repositioning the conversion window to conform to the new location or size of the target window.

If you want users of your application to have the ability to enter Kanji characters, the application must handle Windows IME messages. For more information on IME programming, see the Internationalization Handbook for Software Design in the Microsoft Development Library.

Visual C++ Debugger

The Visual C++ debugger provides the ability to set breakpoints on IME messages. In addition, the Memory window can display double-byte characters.

Command-Line Tools

The Visual C++ command-line tools, including the compiler, NMAKE, and the resource compiler (RC.EXE), are MBCS-enabled. You can use the resource compiler’s /c option to change the default code page when compiling your application’s resources.

To change the default locale at source code compile time, use #pragma setlocale.

Graphical Tools

The Visual C++ Windows-based tools, such as Spy++ and the resource editing tools, fully support IME strings.

See Also MBCS Programming Tips


MBCS Programming Tips

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

This section supplies tips for successful multibyte character set (MBCS) programming. The advice applies to MFC applications and applications written without MFC. Topics include:

  • General MBCS programming advice

  • Incrementing and decrementing pointers

  • Byte indices

  • Last character in a string

  • Character assignment

  • Character comparison

  • Buffer overflow


General MBCS Programming Advice

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Use the following tips:

  • For flexibility, use run-time macros such as _tcschr and _tcscpy when possible. For more information, see Generic-Text Mappings in TCHAR.H.

  • Use the C run-time _getmbcp function to get information about the current code page.

  • Do not reuse string resources. Depending on the target language, a given string may have a different meaning when translated. For example, “File” on the application’s main menu might translate differently from the string “File” in a dialog box. If you need to use more than one string with the same name, use different string IDs for each.

  • You may want to find out whether or not your application is running on an MBCS-enabled operating system. To do so, set a flag at program startup; do not rely on API calls.

  • When designing dialog boxes, allow approximately 30% extra space at the end of static text controls, to allow for MBCS translation.

  • Be careful when selecting fonts for your application, because some fonts are not available on all systems. For example, the Japanese version of Windows NT does not support the Helvetica font.

  • When designing your application, decide which strings can or cannot be localized. If in doubt, assume that any given string will be localized. As such, do not mix strings that can be localized with those that cannot.

See Also Incrementing and Decrementing Pointers


Incrementing and Decrementing Pointers

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Use the following tips:

  • Point to lead bytes, not trail bytes. It is usually unsafe to have a pointer to a trail byte. It’s usually safer to scan a string forward rather than in reverse.

  • There are pointer increment/decrement functions and macros available that move over a whole character:
    sz1++;

    becomes

    sz1 = _mbsinc( sz1 );

    The _mbsinc and _mbsdec functions correctly increment and decrement in character units, regardless of the character size.

  • For decrements, you need a pointer to the head of the string, as in the following:
    sz2--;

    becomes

    sz2 = _mbsdec( sz2Head, sz2 );

    Alternatively, your “head” pointer could be to a valid character in the string, such that

    sz2Head < sz2

    You must have a pointer to a known valid lead byte.

  • You may want to maintain a pointer to the previous character for faster calls to _mbsdec.

See Also Byte Indices


Byte Indices

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Use the following tips:

  • Working with a bytewise index into a string presents problems similar to those posed by pointer manipulation. Consider this example, which scans a string for a backslash character:
    while ( rgch[ i ] != '\\' )
    i++;

    This may index a trail byte, not a lead byte, and thus it may not point to a character.

  • Use the _mbslen function to solve the preceding problem:
    while ( rgch[ i ] != '\\' )
    i += _mbslen( rgch + i );

    This correctly indexes to a lead byte, hence to a character. The _mbslen function determines the size of a character (one or two bytes).

See Also The Last Character in a String


The Last Character in a String

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Use the following tips:

  • Trail byte ranges overlap the ASCII character set in many cases. You can safely use bytewise scans for any control characters (less than 32).

  • Consider the following line of code, which might be checking to see if the last character in a string is a backslash character:
    if ( sz[ strlen( sz ) - 1 ] == '\\' )    // Is last character a '\'?
    // . . .

    Since strlen is not “MBCS-aware,” it will return the number of bytes, not the number of characters, in a multibyte string. Also, note that in some code pages (932, for example), ‘\’ (0x5c) is a valid trail byte (sz is a C string).

    One possible solution is to rewrite the code this way:

    char *pLast;
pLast = _mbsrchr( sz, '\\' );    // find last occurrence of '\' in sz
if ( pLast && ( *_mbsinc( pLast ) == '\0' ) )
    // . . .

    This code uses the MBCS functions _mbsrchr and _mbsinc. Because these functions are MBCS-aware, they can distinguish between a ‘\’ character and a trail byte ‘\’. The code performs some action if the last character in the string is a null (‘\0’).

See Also Character Assignment


Character Assignment

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Consider the following example, in which the while loop scans a string, copying all characters except ‘X’ into another string:

while( *sz2 )
{
    if( *sz2 != 'X' )
        *sz1++ = *sz2;
    else
        sz2++;
}

The code copies the byte at sz2 to the location pointed to by sz1, then increments sz1 to receive the next byte. But if the next character in sz2 is a double-byte character, the assignment to sz1 will copy only the first byte. The following code uses a portable function to copy the character safely and another to increment sz1 and sz2 correctly:

while( *sz2 )
{
    if( *sz2 != 'X' )
    {
        _mbscpy( sz1, sz2 );
        sz1 = _mbsinc( sz1 );
    }
    else
        sz2 = _mbsinc( sz2 );
}

See Also Character Comparison


Character Comparison

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Use the following tips:

  • Comparing a known lead byte with an ASCII character works correctly:
    if( *sz1 == 'A' )
  • Comparing two unknown characters requires the use of one of the macros defined in MBSTRING.H:
    if( !_mbccmp( sz1, sz2) )

    This ensures that both bytes of a double-byte character are compared for equality.

See Also Buffer Overflow


Buffer Overflow

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

Varying character sizes can cause problems when you put characters into a buffer. Consider the following code, which copies characters from a string, sz, into a buffer, rgch:

cb = 0;
while( cb < sizeof( rgch ) )
    rgch[ cb++ ] = *sz++;

The question is: Was the last byte copied a lead byte? The following does not solve the problem because it can potentially overflow the buffer:

cb = 0;
while( cb < sizeof( rgch ) )
{
    _mbccpy( rgch + cb, sz );
    cb += _mbclen( sz );
    sz = _mbsinc( sz );
}

The _mbccpy call attempts to do the right thing — copy the full character, whether it’s one or two bytes. But it doesn’t take into account that the last character copied may not fit the buffer if the character is two bytes wide. The correct solution is:

cb = 0;
while( (cb + _mbclen( sz )) <= sizeof( rgch ) )
{
    _mbccpy( rgch + cb, sz );
    cb += _mbclen( sz );
    sz = _mbsinc( sz );
}

This code tests for possible buffer overflow in the loop test, using _mbclen to test the size of the current character pointed to by sz. By making a call to the _mbsnbcpy function, you can replace the code in the while loop with a single line of code. For example:

cb = 0;
while( (cb + _mbclen( sz )) <= sizeof( rgch ) )
{
    _mbsnbcpy( rgch, sz, sizeof( rgch ) );
}


Generic-Text Mappings in TCHAR.H

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

To simplify transporting code for international use, the Microsoft run-time library provides Microsoft-specific “generic-text” mappings for many data types, routines, and other objects. You can use these mappings, which are defined in TCHAR.H, to write generic code that can be compiled for single byte, multibyte, or Unicode, depending on a manifest constant you define using a #define statement. Generic-text mappings are Microsoft extensions that are not ANSI compatible.

Using the header file TCHAR.H, you can build single-byte, MBCS, and Unicode applications from the same sources. TCHAR.H defines macros prefixed with _tcs, which, with the correct preprocessor definitions, map to str, _mbs, or wcs functions as appropriate. To build MBCS, define the symbol _MBCS. To build Unicode, define the symbol _UNICODE. To build a single-byte application, define neither (the default). By default, _MBCS is defined for MFC applications.

The _TCHAR data type is defined conditionally in TCHAR.H. If the symbol _UNICODE is defined for your build, _TCHAR is defined as wchar_t; otherwise, for single-byte and MBCS builds, it is defined as char. (wchar_t, the basic Unicode wide character data type, is the 16-bit counterpart to an 8-bit signed char.) For international applications, use the _tcs family of functions, which operate in _TCHAR units, not bytes. For example, _tcsncpy copies n _TCHARs, not n bytes.

Because some SBCS string-handling functions take (signed) char* parameters, a type mismatch compiler warning will result when _MBCS is defined. There are three ways to avoid this warning, listed in order of efficiency:

  1. Use the “type-safe” inline function thunks in TCHAR.H. This is the default behavior.

  2. Use the “direct” macros in TCHAR.H by defining _MB_MAP_DIRECT on the command line. If you do this, you must manually match types. This is the fastest method, but is not type-safe.

  3. Use the “type-safe” statically-linked library function thunks in TCHAR.H. To do so, define the constant _NO_INLINING on the command line. This is the slowest method, but the most type-safe.

Preprocessor Directives for Generic-Text Mappings

# define | Compiled Version | Example
_UNICODE | Unicode (wide-character) | _tcsrev maps to _wcsrev
_MBCS | Multibyte-character | _tcsrev maps to _mbsrev
None (the default: neither _UNICODE nor _MBCS defined) | SBCS (ASCII) | _tcsrev maps to strrev

For example, the generic-text function _tcsrev, defined in TCHAR.H, maps to _mbsrev if you defined _MBCS in your program, or to _wcsrev if you defined _UNICODE. Otherwise _tcsrev maps to strrev. Other data type mappings are provided in TCHAR.H for programming convenience, but _TCHAR is the most useful.

Generic-Text Data Type Mappings

Generic-Text Data Type Name | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_TCHAR | char | char | wchar_t
_TINT | int | int | wint_t
_TSCHAR | signed char | signed char | wchar_t
_TUCHAR | unsigned char | unsigned char | wchar_t
_TXCHAR | char | unsigned char | wchar_t
_T or _TEXT | No effect (removed by preprocessor) | No effect (removed by preprocessor) | L (converts following character or string to its Unicode counterpart)

For a complete list of generic-text mappings of routines, variables, and other objects, see Appendix B, Generic-Text Mappings in the Run-Time Library Reference.

Note Do not use the str family of functions with Unicode strings, which are likely to contain embedded null bytes. Similarly, do not use the wcs family of functions with MBCS (or SBCS) strings.

The following code fragments illustrate the use of _TCHAR and _tcsrev for mapping to the MBCS, Unicode, and SBCS models.

_TCHAR *RetVal, *szString;
RetVal = _tcsrev(szString);

If _MBCS has been defined, the preprocessor maps this fragment to the code:

char *RetVal, *szString;
RetVal = _mbsrev(szString);

If _UNICODE has been defined, the preprocessor maps this fragment to the code:

wchar_t *RetVal, *szString;
RetVal = _wcsrev(szString);

If neither _MBCS nor _UNICODE has been defined, the preprocessor maps the fragment to single-byte ASCII code:

char *RetVal, *szString;
RetVal = strrev(szString);

Thus you can write, maintain, and compile a single source code file to run with routines that are specific to any of the three kinds of character sets.

See Also Using TCHAR.H Data Types with _MBCS Code


Using TCHAR.H Data Types with _MBCS Code

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

When the manifest constant _MBCS is defined, a given generic-text routine maps to one of the following kinds of routines:

  • An SBCS routine that handles multibyte bytes, characters, and strings appropriately. In this case, the string arguments are expected to be of type char*. For example, _tprintf maps to printf; the string arguments to printf are of type char*. If you use the _TCHAR generic-text data type for your string types, the formal and actual parameter types for printf match because _TCHAR* maps to char*.

  • An MBCS-specific routine. In this case, the string arguments are expected to be of type unsigned char*. For example, _tcsrev maps to _mbsrev, which expects and returns a string of type unsigned char*. If you use the _TCHAR generic-text data type for your string types, there is a potential type conflict because _TCHAR maps to type char.

Following are three solutions for preventing this type conflict (and the C compiler warnings or C++ compiler errors that would result).

  • Use the default behavior. TCHAR.H provides generic-text routine prototypes for routines in the run-time libraries, as in the following example.
    char * _tcsrev(char *);

    In the default case, the prototype for _tcsrev maps to _mbsrev through a thunk in LIBC.LIB. This changes the types of the _mbsrev incoming parameters and outgoing return value from _TCHAR * (that is, char *) to unsigned char *. This method ensures type matching when you are using _TCHAR, but it is relatively slow due to the function call overhead.

  • Use function inlining by incorporating the following preprocessor statement in your code.
    #define _USE_INLINING

    This method causes an inline function thunk, provided in TCHAR.H, to map the generic-text routine directly to the appropriate MBCS routine. The following code excerpt from TCHAR.H provides an example of how this is done.

    __inline char *_tcsrev(char *_s1)
{return (char *)_mbsrev((unsigned char *)_s1);}

    If you can use inlining, this is the best solution, because it guarantees type matching and has no additional time cost.

  • Use “direct mapping” by incorporating the following preprocessor statement in your code.
    #define _MB_MAP_DIRECT

    This approach provides a fast alternative if you do not want to use the default behavior or cannot use inlining. It causes the generic-text routine to be mapped by a macro directly to the MBCS version of the routine, as in the following example from TCHAR.H.

    #define _tcschr _mbschr

    When you take this approach, you must be careful to ensure use of appropriate data types for string arguments and string return values. You can use type casting to ensure proper type matching or you can use the _TXCHAR generic-text data type. _TXCHAR maps to type char in SBCS code but maps to type unsigned char in MBCS code. For more information about generic-text macros, see Appendix B, Generic-Text Mappings in the Run-Time Library Reference.


For More Information

Home | Unicode Tasks | Multibyte Character Set (MBCS) Tasks

For more information on developing for international markets, see the following:

  • In the Run-Time Library Reference: Internationalization.

  • In the Win32 Programmer’s Reference: String Manipulation.

  • In Advanced Windows NT, Microsoft Press, 1994, by Jeffrey Richter: Chapter 11, Unicode.

  • The Unicode™ Standard: Worldwide Character Encoding, Version 1.0, Volumes 1 and 2, Addison-Wesley, 1992.


Internet Topics

Home | Overview | How Do I

This family of Internet articles provides information to help you become familiar with the major technologies for programming for the Internet.

What do you want to know more about?

  • Active Technology on the Internet, ActiveX controls, Active documents, ISAPI, WinInet

  • Internet first steps: Designing Internet applications and using MFC’s Internet support

  • Internet programming with WinInet: Internet client applications

  • Internet Server API (ISAPI) extensions and filters

  • Internet First Steps: Application Design Choices

  • Internet First Steps: Writing MFC Applications


Internet: Where Is...

Home | Overview | How Do I

This article will help you locate Internet topics of interest in Visual C++ Programmer's Guide and the Class Library Reference. You can get to this article from all main Internet topics through the See Also list on those topics. This article is organized into the following categories:

  • Internet Overviews

  • Internet-Related MFC Classes

  • Internet Information by Topic

  • Internet Samples

  • Web Sites for More Information

Internet Overviews

For overviews and general information about MFC Internet programming, see:

  • Internet First Steps

  • ActiveX Controls

  • Active Documents

  • Asynchronous Monikers

  • Internet Server Programming with ISAPI

  • Internet Client Programming with WinInet

Internet-Related MFC Classes

For information about Internet-related classes, see:

Global classes
AfxParseURL
AfxGetInternetHandleType
ActiveX control classes
COleControl
Active document classes
CDocObjectServer
CDocObjectServerItem
Asynchronous moniker classes
CAsyncMonikerFile
CDataPathProperty
ISAPI classes
CHttpServer
CHttpServerContext
CHttpFilter
CHttpFilterContext
CHtmlStream
WinInet classes
CInternetSession
CInternetConnection
CFtpConnection
CGopherConnection
CHttpConnection
CInternetFile
CGopherFile
CHttpFile
CFileFind
CFtpFileFind
CGopherFileFind
CGopherLocator
CInternetException

Internet Information by Topic

For information on programming with a specific Internet technology, see:

Overviews | ISAPI Server Extensions and Filters Internet First Steps: ISAPI Server Extensions and Filters Frequently Asked Questions: About Internet Programming Internet Server API (ISAPI) Extensions ISAPI Extensions: MFC Classes ISAPI: Extending Web Servers
Filters | ISAPI Extensions: Filters Steps to Create a Typical ISAPI Filter
Servers | ISAPI Extensions: Servers ISAPI Extensions: Parse Maps Steps to Create a Typical ISAPI Extension
 | ISAPI and Databases
Debugging | ISAPI: Debugging
Designing | ISAPI Programming Tips

WinInet |
Overviews | WinInet (HTTP, FTP, Gopher) Internet First Steps: WinInet Internet Programming with WinInet How WinInet Makes It Easier to Create Internet Client Applications How MFC Makes It Easier to Create Internet Client Applications
Steps in creating WinInet applications | Prerequisites for Internet Client Classes Writing an Internet Client Application Using MFC WinInet Classes Steps in a Typical Internet Client Application Steps in a Typical FTP Client Application Steps in a Typical HTTP Client Application Steps in a Typical Gopher Client Application Steps in a Typical HTTP Client Application

Internet Samples

For Internet sample programs, see:

Sample | Location
COM components (Internet server extensions) | WWWQUOTE MFCUCASE COUNTER
Active documents | BINDSCRB
General | HTTPSVR
WinInet | FTPTREE TEAR

Web Sites for More Information

For additional information on Microsoft’s Internet technology, see the Microsoft Developer Network Online Web site:

http://www.microsoft.com/msdn

This Web site for developers contains information on using Microsoft development tools and technologies, and top stories about recent and upcoming conferences. From this page, you can jump to many related developer sites, including the Internet Development toolbox. You can also download beta SDKs and samples.

For information on the ActiveX Software Development Kit, use this URL:

http://www.microsoft.com/intdev/sdk

The World Wide Web Consortium (W3C) publishes specifications for HTML, HTTP, CGI, and other World Wide Web technologies. Its URL is:

http://www.w3.org/pub/WWW/

Note Web links may change without notice.

More Internet Help

The OLE section of the Win32 SDK documentation contains additional information about OLE programming. This information provides details about using the Win32 WinInet and ISAPI functions directly, rather than through the MFC classes. It also contains overview information about Internet technologies.


Internet First Steps

Home | Overview | How Do I

In this family of articles, you'll read detailed steps for adding Internet support to your applications. Topics include how to use the new MFC classes to Internet-enable your existing applications, how to FTP a file, and how to add Active document support to your existing COM component. Do you want to create a document with up-to-the-minute stock quotes, Pittsburgh's football scores, and the latest temperature in Antarctica? Microsoft provides a number of technologies to help you do that over the Internet.

Active technologies include ActiveX controls (formerly OLE controls) and Active documents; ISAPI for creating COM components (Internet server extensions and filters); WinInet for easily retrieving and saving files across the Internet; and asynchronous monikers for efficient data downloading. Visual C++ provides wizards to help you get started quickly with a starter application. For an introduction to these technologies, see Internet Support: Overview and Active Technology Topics.

Have you always wanted to FTP a file but haven't learned WinSock and network programming protocols? WinInet classes encapsulate these protocols, providing you with a simple set of functions you can use to write a client application on the Internet to download files using HTTP, FTP, and gopher. You can use WinInet to search directories on your hard drive or around the world. You can transparently collect data of several different types, and present it to the user in an integrated interface.

Do you have large amounts of data to download? Asynchronous monikers provide a COM (Component Object Model) solution for progressive rendering of large objects. WinInet can also be used asynchronously.

Do you want to run a custom application on your Web server? ISAPI server extension classes provide a way to do that. ISAPI filters let you track and examine selected data sent to your Web server.

The following table describes a few of the things you can do with these technologies.

You have | You want to | You should
A Web server. | Track logons and detailed information about URL requests. | Write an ISAPI filter, request notifications for logon events and URL mapping.
A Web browser. | Provide dynamic content. | Create ActiveX controls and Active documents.
Clients with different browsers connecting to your server. | Change HTML data sent from server to client, so people with newer browsers get the latest features, and people with older browsers can still read the information. | Write an ISAPI filter.
A document-based application. | Add support to FTP a file. | Use WinInet or asynchronous monikers.

See the following topics for details to get you started:

  • Internet First Steps: Application Design Choices

  • Internet First Steps: Writing MFC Applications

  • Internet First Steps: ActiveX Controls

  • Internet First Steps: Active Documents

  • Internet First Steps: Asynchronous Monikers

  • Internet First Steps: ISAPI Server Extensions and Filters

  • Internet First Steps: WinInet

See Also Internet: Where Is...


Internet First Steps: Application Design Choices

Home | Overview | How Do I

This article discusses some of the design issues to consider when programming for the Internet. It also describes the sample applications available.

Topics covered in this article include:

  • Intranet Versus Internet

  • Client or Server Application

  • The Web Page: HTML, Active Documents, ActiveX Controls

  • Browser or Stand-Alone Application

  • COM on the Internet

  • Client Data Download Services

  • Server Extensions and Filters

  • Samples

If you are ready to start writing your program now, see Internet First Steps: Writing MFC Applications.

Intranet Versus Internet

Many applications run on the Internet and are accessible to anyone with a browser and Internet access. Businesses are also implementing intranets, which are company-wide networks using TCP/IP protocols and Web browsers. Intranets offer an easily upgradeable, central source for company-wide information. They can be used for upgrading software, for delivering and tabulating surveys, for customer support, and for information delivery. The following table compares features of the Internet and intranets.

Internet | Intranet
Low bandwidth | High bandwidth
Reduced security of data and systems | Controlled access to data and systems
Minimal control of content | High control of content

Client or Server Application

Your application may run on a client computer or on a server computer. Your application may also be stored on a server, and then downloaded across the Internet and run on a client computer. MFC WinInet classes are used for client applications to download files. MFC and asynchronous moniker classes are used to download files and control properties. MFC ISAPI classes are used for server applications. Classes for ActiveX controls and Active documents are used for client applications and for applications that are downloaded from the server to run on a client.

The Web Page: HTML, Active Documents, ActiveX Controls

Microsoft offers several ways of providing content on a Web page. Web pages can use standard HTML or HTML extensions, such as the object tag, to provide dynamic content such as ActiveX controls.

Web browsers typically display HTML pages. Active documents can also display your application's data in the simple point-and-click interface of a COM-enabled browser. Your Active document server can display your document, full frame in the entire client area, with its own menus and toolbars.

ActiveX controls you write can be downloaded asynchronously from the server and displayed on a Web page. You can use a scripting language such as VBScript to perform client-side validation before sending information to the server.

Browser or Stand-Alone Application

You can write ActiveX controls that are embedded in an HTML page and Active document servers that are viewed in a browser. You can write HTML pages that contain a button to submit a request to run your ISAPI application on a Web server. You can write a stand-alone application that uses Internet protocols to download files and display the information to your user, without ever using a browser application.

COM on the Internet

ActiveX controls, Active documents, and asynchronous monikers all use COM (Component Object Model) technologies.

ActiveX controls provide dynamic content to documents and pages on Internet sites. With COM you can build ActiveX controls and full-frame documents using Active documents.

Asynchronous monikers provide features to enable a control to perform well in an Internet environment, including an incremental or progressive means to download data. Controls must also work well with other controls that may also be retrieving their data asynchronously at the same time.

Client Data Download Services

Two sets of APIs that will help transfer data to your client are WinInet and asynchronous monikers. If you have large .gif and .avi files and ActiveX controls on your HTML page, you can increase the responsiveness to the user by downloading asynchronously, either by using asynchronous monikers or using WinInet asynchronously.

A common task on the Internet is transferring data. If you are already using Active technology (for example, if you have an ActiveX control), you can use asynchronous monikers to progressively render data as it downloads. You can use WinInet to transfer data using common Internet protocols like HTTP, FTP, and gopher. Both methods provide protocol independence, and provide an abstract layer to using WinSock and TCP/IP. You can still use WinSock directly.

The following table summarizes several ways of using MFC to transfer data across the Internet.

Use this protocol | Under these conditions | Using these classes
Internet Downloading Using Asynchronous Monikers | For asynchronous transfer using COM, ActiveX controls, and any Internet protocol. | CAsyncMonikerFile, CDataPathProperty
WinInet | For Internet protocols for HTTP, FTP, and gopher. Data can be transferred synchronously or asynchronously and is stored in a system-wide cache. | CInternetSession, CFtpFileFind, CGopherFileFind, and many more.
WinSock | For maximum efficiency and control. Requires understanding of sockets and TCP/IP protocols. | CSocket, CAsyncSocket

Server Extensions and Filters

The Internet Server API (ISAPI) provides a simple and efficient way to extend any ISAPI-compliant Web server. You can write ISAPI server extension DLLs (ISAs) that can be loaded and called by the HTTP server. An ISA is invoked from a browser application and can be used for database applications using forms processing, or to provide other custom functionality.

You can write an ISAPI filter to register for notification of events such as logging on or URL mapping. When the selected events occur, the filter is called, and you can monitor and change the data (on its way from the server to the client or vice versa).

Both server extensions and filters run in the process space of the Web server, providing an efficient way to extend the server's capabilities.

See Also Internet: Where Is..., Internet Programming with WinInet, Internet Downloading Using Asynchronous Monikers


Internet First Steps: Writing MFC Applications

Home | Overview | How Do I

This article explains the initial steps you take to develop your application. First, you must decide what kind of application you are writing. Several of the choices were discussed in Internet First Steps: Application Design Choices. Will your application be:

  • Running on the Internet or an intranet?

  • Running on a client or on a server?

  • Running in a browser or as a stand-alone application?

  • Using COM or Active technology?

  • Downloading data using WinInet or asynchronous monikers?

  • A server extension or a filter?

Your decisions determine which classes are appropriate for your application. Your answers also help determine the selections you make when you run AppWizard to begin constructing your application.

After you've made your initial design decisions about your Internet application, you can use AppWizard to get started. Use AppWizard to create a skeleton application and modify the code as described in the following articles:

  • For an ISAPI filter, see Steps to Create a Typical ISAPI Filter.

  • For an ISAPI server extension, see Steps to Create a Typical ISAPI Extension.

  • For an ActiveX control, see Internet First Steps: ActiveX Controls.

  • For an Active document, see Internet First Steps: Active Documents.

The following articles also provide instructions to help you start your programming tasks:

  • Internet First Steps: Application Design Choices

  • Internet First Steps: Asynchronous Monikers

  • Internet First Steps: ISAPI Server Extensions and Filters

  • Internet First Steps: WinInet

See Also Internet: Where Is...


Internet First Steps: ActiveX Controls

Home | Overview | How Do I

To be an ActiveX control, your control must be a COM object, export DLLRegisterServer and DLLUnRegisterServer, and implement the IUnknown interface.

ActiveX controls are not limited to the Internet. An ActiveX control can also be used in any container, as long as the control supports the interfaces required by that container. Topics included in this article that describe how to create ActiveX controls for the Internet are:

  • Making Your Existing Controls Internet-Friendly

  • How Do I Create a New ActiveX Control?

  • How Do I Update an Existing OLE Control to Use New ActiveX Control Features?

  • Displaying a Control on a Web Page

  • How Do I Decide Whether to Derive from CDataPathProperty or CCachedDataPathProperty?

Making Your Existing Controls Internet-Friendly

You can use your existing controls on the Internet. However, there are steps you should take to make your code size smaller and to make your control properties download asynchronously.

The following tips will make your applications run better on the Internet.

  • Be asynchronous; don't hold up other programs.

  • Download code and properties in the background.

  • Download data in small blocks.

  • Become user-interface active as quickly as possible.

  • Write efficient routines to keep code size and run time down.

For more information on increasing your control's performance, see ActiveX Controls: Optimization.

Creating a New ActiveX Control

When creating a new control using AppWizard, you can choose to enable support for asynchronous monikers as well as other optimizations. To add support to download control properties asynchronously, follow these steps:

To create your project using the MFC ActiveX ControlWizard

  1. Select New on the File menu.

  2. Click the Projects tab, select MFC ActiveX ControlWizard, and name your project.

  3. In Step 2 of the MFC ActiveX ControlWizard, click the Advanced button.

    In the Advanced ActiveX Features dialog box, select Loads Properties Asynchronously. Selecting this option sets up the ready state property and the ready state changed event for you.

    You can also select other optimizations, such as Windowless Activation, which is described in ActiveX Controls: Optimization.

  4. In the Advanced ActiveX Features dialog box, click OK.

  5. Choose Finish to create the project.

To create a class derived from CDataPathProperty

  1. Create a class derived from CDataPathProperty.

  2. In each of your source files that includes the header file for your control, add the header file for this class before it.

  3. In this class, override OnDataAvailable. This function is called whenever data is available for display. As data becomes available, you can handle it any way you choose, for example by progressively rendering it.

    The code excerpt below is a simple example of progressively displaying data in an edit control. Note the use of flag BSCF_FIRSTDATANOTIFICATION to clear the edit control.

    void CMyDataPathProperty::OnDataAvailable(DWORD dwSize, DWORD bscfFlag)
{
        CListCtrl list_ctrl;
        CEdit* edit=list_ctrl.GetEditControl();
        if (bscfFlag & BSCF_FIRSTDATANOTIFICATION && edit->m_hWnd)
        {
            edit->SetSel(0, -1);
            edit->Clear();
        }
        if (!dwSize)
            return;

    CString string;
    LPTSTR str=string.GetBuffer(dwSize);
    UINT nBytesRead=Read(str, dwSize);
    if (!nBytesRead)
            return;
        string.ReleaseBuffer(nBytesRead);
        edit->SetSel(-1, -1);
        edit->ReplaceSel(string);
}

    Note that you must include AFXCMN.H to use the CListCtrl class.

  4. When your control's overall state changes (for example, from loading to initialized or user interactive), call COleControl::InternalSetReadyState. If your control has only one data path property, you can add code on BSCF_LASTDATANOTIFICATION to notify the container that your download is complete. For example:
    if (bscfFlag == BSCF_LASTDATANOTIFICATION)
{
    GetControl()->InternalSetReadyState(READYSTATE_COMPLETE);
}
  5. Override OnProgress. In OnProgress, you are passed a number showing the maximum range and a number showing how far along the current download is. You can use these numbers to display status such as percent complete to the user.

In the next procedure, you will be adding a property to your control to use the class you just derived.

To add a property using ClassWizard

  1. In the MFC ClassWizard dialog box, click the Automation tab and make sure your control class (the class derived from COleControl) is selected.

  2. Choose Add Property, and in the Add Property dialog box select Get/Set methods.

  3. Type a variable name in the External name box, for example, EditControlText, and select BSTR as its type.

    This adds the member variable, modifies the IDL, and adds the dispatch map and Get/Set functions.

  4. Declare a member variable of your CDataPathProperty derived class to your ActiveX control class.
    CMyDataPathProperty EditControlText;
  5. Implement the Get/Set member functions. For the Get function, return the string. For Set, load the property and call SetModifiedFlag.
    BSTR CDataPathCtrl::GetDataPath()
{
    CString strResult;
    strResult = EditControlText.GetPath();
    return strResult.AllocSysString();
}
void CDataPathCtrl::SetDataPath(LPCTSTR lpszNewValue)
{
    Load(lpszNewValue, EditControlText);
    SetModifiedFlag();
}
  6. In DoPropExchange, add the following line:
    PX_DataPath(pPX, _T("DataPath"), EditControlText);
  7. Override ResetData to notify the property to reset its control by adding this line:
    EditControlText.ResetData();

Deciding Whether to Derive from CDataPathProperty or CCachedDataPathProperty

The previous example describes steps for deriving your control's property from CDataPathProperty. This is a good choice if you are downloading real-time data that frequently changes, and for which you do not need to keep all the data, but only the current value. An example is a stock ticker control.

You can also derive from CCachedDataPathProperty. In this case, the downloaded data is cached in a memory file. This is a good choice if you need to keep all the downloaded data — for example, a control that progressively renders a bitmap. In this case, the class has a member variable containing your data:

    CMemFile m_Cache;

In your ActiveX control class, you can use this memory mapped file in OnDraw to display the data. In your ActiveX control CCachedDataPathProperty derived class, override the member function OnDataAvailable and invalidate the control, after calling the base class implementation.

COleControl OLEctrl;

void CMyCachedDataPathProperty::OnDataAvailable(DWORD dwSize, DWORD bscfFlag)
{
    CCachedDataPathProperty:OnDataAvailable(dwSize, bscfFlag);
    OLEctrl.InvalidateControl(NULL);
}

Downloading Data Asynchronously Using ActiveX Controls

Downloading data over a network should be done asynchronously. The advantage of doing so is that if a large amount of data is transferred or if the connection is slow, the download process will not block other processes on the client.

Asynchronous monikers provide a way to download data asynchronously over a network. A Read operation on an Asynchronous moniker returns immediately, even if the operation has not been completed.

For example, if only 10 bytes are available and Read is called asynchronously on a 1K file, Read does not block, but returns with the currently available 10 bytes.

You implement asynchronous monikers using the CAsyncMonikerFile class. However, ActiveX controls can use the CDataPathProperty class, which is derived from CAsyncMonikerFile, to help implement asynchronous control properties.

The ASYNDOWN sample demonstrates how to set up an asynchronous loop using timers to read the data. ASYNDOWN is described in detail in the KB article "FILE: AsyncDown Demonstrates Asynchronous Data Download" (006415), and is available for download from the Microsoft Software Library. (For more information about downloading files from the Microsoft Software Library, please see the article How to Obtain Microsoft Support Files from Online Services (Q119591) in the Microsoft Knowledge Base.)

The basic technique used in ASYNDOWN is to set a timer in CDataPathProperty::OnDataAvailable to indicate when data is available. When the timer message is received, the application reads in 128-byte blocks of data and fills an edit control. If data is not available when the timer message is handled, the timer is turned off. OnDataAvailable turns on the timer if more data arrives later.

Displaying a Control on a Web Page

Here is an example of an object tag and attributes for inserting a control on a Web page.

<OBJECT
CLASSID="clsid:FC25B780-75BE-11CF-8B01-444553540000"
CODEBASE="/ie/download/activex/iechart.ocx"
ID=chart1
WIDTH=400
HEIGHT=200
ALIGN=center
HSPACE=0
VSPACE=0
>
<PARAM NAME="BackColor" value="#ffffff">
<PARAM NAME="ForeColor" value="#0000ff">
<PARAM NAME="url" VALUE="/ie/controls/chart/mychart.txt">
</OBJECT>

A W3C Working Draft is currently under review for the object tag. See the draft for details of object tags and attributes. A list of current W3C working drafts, including this one, can be found at:

http://www.w3.org/pub/WWW/TR

See Also Internet: Where Is..., ActiveX Controls on the Internet

Updating an Existing OLE Control to Use New ActiveX Control Features

If your OLE control was created with a version of Visual C++ prior to 4.2, there are steps you can take to improve its performance and enhance its functionality. For a detailed discussion of these changes, see ActiveX Controls: Optimization.

If you are adding asynchronous property support to an existing control, you will need to add the ready state property and the ReadyStateChange event yourself. ClassWizard provides stock implementation of these. In the constructor for your control, add:

m_lReadyState = READYSTATE_LOADING;

You will update the ready state as your code is downloaded by calling COleControl::InternalSetReadyState. One place you could call InternalSetReadyState is from the OnProgress override of CDataPathProperty derived class.

Then, follow the steps in How do I create a new ActiveX control?


Internet First Steps: Upgrading an Existing ActiveX Control

Existing ActiveX controls (formerly OLE controls) can be used on the Internet without modification. However, you may want to modify controls to improve their performance. When using your control on a Web page, there are additional considerations. The .ocx file and all supporting files must be on the target machine or be downloaded across the Internet. This makes code size and download time an important consideration. Downloads can be packaged in a signed .cab file. You can mark your control as safe for scripting, and as safe for initializing.

This article discusses the following topics:

  • Packaging Code for Downloading

  • Marking a Control Safe for Scripting and Initializing

  • Licensing Issues

  • Signing Code

  • Managing the Palette

  • Internet Explorer Browser Safety Levels and Control Behavior

You can also add optimizations, as described in ActiveX Controls: Optimization. Monikers can be used to download properties and large BLOBs asynchronously, as described in How Do I Update an Existing OLE Control to Use New ActiveX Control Features.

Packaging Code for Downloading

The CODEBASE Tag

ActiveX controls are embedded in Web pages using the <OBJECT> tag. The CODEBASE parameter of the <OBJECT> tag specifies the location from which to download the control. CODEBASE can point at a number of different file types successfully.

Using the CODEBASE Tag with an OCX File

CODEBASE="http://www.mysite.com/mycontrol.ocx#version=4,70,0,1086"

This solution downloads only the control's .ocx file, and requires any supporting DLLs to already be installed on the client machine. This will work for Internet Explorer 3.0 and MFC ActiveX controls built with Visual C++ 4.0 and 4.1, since Internet Explorer 3.0 ships with the supporting DLLs for Visual C++ 4.0 and 4.1 controls. If another Internet browser that is ActiveX control-capable is used to view this control, this solution will not work.

Using the CODEBASE Tag with an INF File

CODEBASE="http://www.mysite.com/trustme.inf"

An .inf file will control the installation of an .ocx and its supporting files. This method is not recommended because it is not possible to sign an .inf file (see Signing Code for pointers on code signing).

Using the CODEBASE Tag with a CAB File

CODEBASE="http://www.somesite.com/acontrol.cab#version=1,2,0,0"

Cabinet files are the recommended way to package ActiveX controls that use MFC. Packaging an MFC ActiveX control in a cabinet file allows an .inf file to be included to control installation of the ActiveX control and any dependent DLLs (such as the MFC DLLs). Using a CAB file automatically compresses the code for quicker download. If you are using a .cab file for component download, it is faster to sign the entire .cab file than each individual component.

Creating CAB Files

The CABinet Development Kit can be obtained from the Microsoft developers Web site, http://www.microsoft.com/workshop/. In this kit you will find the necessary tools to construct cabinet files.

The cabinet file pointed to by CODEBASE should contain the .ocx file for your ActiveX control and an .inf file to control its installation. You create the cabinet file by specifying the name of your control file and an .inf file. Do not include dependent DLLs that may already exist on the system in this cabinet file. For example, the MFC DLLs are packaged in a separate cabinet file and referred to by the controlling .inf file.

For details on how to create a CAB file, see Creating a CAB file.

The INF File

The following example, spindial.inf, lists the supporting files and the version information needed for the MFC Spindial control. Notice the location for the MFC DLLs is a Microsoft Web site. The mfc50.cab is provided and signed by Microsoft.

Contents of spindial.inf:
[mfc50installer]
file-win32-x86=http://activex.microsoft.com/controls/vc/mfc50.cab
[msvcrt.dll] - FileVersion=5,0,0,6164
[mfc50.dll] - FileVersion=5,0,0,6256
[olepro32.dll] - FileVersion=5,0,0,6068

The <OBJECT> Tag

The following example illustrates using the <OBJECT> tag to package the MFC Spindial sample control.

<OBJECT ID="Spindial1" WIDTH=100 HEIGHT=51
  CLASSID="CLSID:06889605-B8D0-101A-91F1-00608CEAD5B3"
  CODEBASE="http://mysite/spindial.cab#Version=1,0,0,001">
    <PARAM NAME="_Version" VALUE="65536">
    <PARAM NAME="_ExtentX" VALUE="2646">
    <PARAM NAME="_ExtentY" VALUE="1323">
    <PARAM NAME="_StockProps" VALUE="0">
    <PARAM NAME="NeedlePosition" VALUE="2">
</OBJECT>

In this case, spindial.cab will contain two files, spindial.ocx and spindial.inf. The following command will build the cabinet file:

C:\CabDevKit\cabarc.exe -s 6144 N spindial.cab spindial.ocx spindial.inf

The –s 6144 parameter reserves space in the cabinet for code signing.

The Version Tag

Note here that the #Version information specified with a CAB file applies to the control specified by the CLASSID parameter of the <OBJECT> tag.

Depending on the version specified, you can force download of your control. For complete specifications of the OBJECT tag including the CODEBASE parameter, see the W3C reference.

Marking a Control Safe for Scripting and Initializing

ActiveX controls used in Web pages should be marked as safe for scripting and safe for initializing if they are in fact safe. A safe control will not perform disk IO or access the memory or registers of a machine directly.

Controls can be marked as safe for scripting and safe for initializing via the registry. Modify DllRegisterServer to add entries similar to the following to mark the control as safe for scripting and persistence in the registry. The ActiveX Base Control sample, available from www.microsoft.com, contains helper functions for adding the necessary keys to the registry. An alternative method is to implement IObjectSafety.

You will define GUIDs (Globally Unique Identifiers) for your control to mark it safe for scripting and for persistence. Controls that can be safely scripted will contain a registry entry similar to the following:

HKEY_CLASSES_ROOT\Component Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}

Controls that can be safely initialized from persistent data are marked safe for persistence with a registry entry similar to:

HKEY_CLASSES_ROOT\Component Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}

Add entries similar to the following (substituting your control's class ID in place of {06889605-B8D0-101A-91F1-00608CEAD5B3}) to associate your keys with the following class ID:

HKEY_CLASSES_ROOT\CLSID\{06889605-B8D0-101A-91F1-00608CEAD5B3}\Implemented Categories\{7DD95801-9882-11CF-9FA9-00AA006C42C4}
HKEY_CLASSES_ROOT\CLSID\{06889605-B8D0-101A-91F1-00608CEAD5B3}\Implemented Categories\{7DD95802-9882-11CF-9FA9-00AA006C42C4}

Licensing Issues

If you want to use a licensed control on a Web page, you must verify that the license agreement allows its use on the Internet and create a license package file(LPK) for it.

A licensed ActiveX control will not load properly in an HTML page if the computer running Internet Explorer is not licensed to use the control. For example, if a licensed control was built using Visual C++, the HTML page using the control will load properly on the computer where the control was built, but it will not load on a different computer unless licensing information is included.

To use a licensed ActiveX control in Internet Explorer, you must check the vendor's license agreement to verify that the license for the control permits:

  • Redistribution

  • Use of the control on the Internet

  • Use of the Codebase parameter

To use a licensed control in an HTML page on a non-licensed machine, you must generate a license package file (LPK). The LPK file contains run-time licenses for licensed controls in the HTML page. This file is generated via LPK_TOOL.EXE which comes with the ActiveX SDK. You can download the ActiveX SDK through the Microsoft Web site http://www.microsoft.com/activex.

To create an LPK file

  1. Run LPK_TOOL.EXE on a computer that is licensed to use the control.

  2. In the License Package Authoring Tool dialog box, in the Available Controls list box, select each licensed ActiveX control that will be used on the HTML page and click Add.

  3. Click Save & Exit and type a name for the LPK file. This will create the LPK file and close the application.

To embed a licensed control on an HTML page

  1. Edit your HTML page. In the HTML page, insert an <OBJECT> tag for the License Manager object before any other <OBJECT> tags. The License Manager is an ActiveX control that is installed with Internet Explorer. Its class ID is shown below. Set the LPKPath property of the License Manager object to the path and name of the LPK file. You can have only one LPK file per HTML page.
    <OBJECT CLASSID = "clsid:5220cb21-c88d-11cf-b347-00aa00a28331">
    <PARAM NAME="LPKPath" VALUE="relative URL to .LPK file">
</OBJECT>
  2. Insert the <OBJECT> tag for your licensed control after the License Manager tag.

    For example, an HTML page that displays the Microsoft Masked Edit control is shown below. The first class ID is for the License Manager control, the second class ID is for the Masked Edit control. Change the tags to point to the relative path of the .lpk file you created earlier, and add an object tag including the class ID for your control.

  3. Insert the <EMBED> attribute for your LPK file, if using the NCompass ActiveX plug-in.

    If your control may be viewed on other Active enabled browsers — for example, Netscape using the NCompass ActiveX plug-in — you must add the <EMBED> syntax as shown below.

    <OBJECT CLASSID="clsid:5220cb21-c88d-11cf-b347-00aa00a28331">
    <PARAM NAME="LPKPath" VALUE="maskedit.lpk">

    <EMBED SRC = "maskedit.LPK">

</OBJECT>
<OBJECT CLASSID="clsid:C932BA85-4374-101B-A56C-00AA003668DC" WIDTH=100 HEIGHT=25>
</OBJECT>

See ActiveX Controls: Licensing an ActiveX Control for more details about control licensing.

Signing Code

Code signing is designed to identify the source of code, and to guarantee that the code has not changed since it was signed. Depending on browser safety settings, users may be warned before the code is downloaded. Users may choose to trust certain certificate owners or companies, in which case code signed by those trusted will be downloaded without warning. Code is digitally signed to avoid tampering.

Make sure your final code is signed so that your control can be automatically downloaded without displaying trust warning messages. For details on how to sign code, check the documentation on Authenticode™ in the ActiveX SDK and see Signing a CAB File. For more information on the Microsoft code-signing initiative, check http://www.microsoft.com/intdev/signcode/.

Depending on trust and browser safety level settings, a certificate may be displayed to identify the signing person or company. If the safety level is none, or if the signed control's certificate owner is trusted, a certificate will not be displayed. See Safety Levels and Control Behavior for details on how the browser safety setting will determine whether your control is downloaded and a certificate displayed.

Digital signing guarantees code has not changed since it's been signed. A hash of the code is taken and embedded in the certificate. This hash is later compared with a hash of the code taken after the code is downloaded but before it runs. Companies such as Verisign can supply private and public keys needed to sign code. The ActiveX SDK ships with MakeCert, a utility for creating test certificates, and two registry files, wvtston.reg and wvtstoff.reg, for specifying whether or not the browser should recognize test certificates as valid.

Managing the Palette

Containers determine the palette and make it available as an ambient property, DISPID_AMBIENT_PALETTE. A container — for example, Microsoft Internet Explorer 3.0 — chooses a palette that is used by all ActiveX controls on a page to determine their own palette. This prevents display flickering and presents a consistent appearance.

A control can override OnAmbientPropertyChange to handle notification of changes to the palette.

A control can override OnGetColorSet to return a color set to draw the palette. Containers use the return value to determine if a control is palette-aware.

Under OCX 96 guidelines, a control must always realize its palette in the background.

Older containers that do not use the ambient palette property will send WM_QUERYNEWPALETTE and WM_PALETTECHANGED messages. A control can override OnQueryNewPalette and OnPaletteChanged to handle these messages.

Internet Explorer Browser Safety Levels and Control Behavior

A browser has options for safety level, configurable by the user. Because Web pages can contain active content that might potentially harm a user's computer, browsers allow the user to select options for safety level. Depending on the way a browser implements safety levels, a control may not be downloaded at all, or will display a certificate or a warning message to allow the user to choose at run time whether or not to download the control. The behavior of ActiveX controls under high, medium, and low safety levels on Internet Explorer is listed below.

High Safety Mode

  • Unsigned controls will not be downloaded.

  • Signed controls will display a certificate if untrusted (a user can choose an option to always trust code from this certificate owner from now on).

  • Only controls marked as safe will have persistent data and/or be scriptable.

Medium Safety Mode

  • Unsigned controls will display a warning before downloading.

  • Signed controls will display a certificate if untrusted.

  • Controls not marked as safe will display a warning.

Low Safety Mode

  • Controls are downloaded without warning.

  • Scripting and persistence occur without warning.

See Also Internet: Where Is..., ActiveX Controls: Licensing an ActiveX Control


Creating Signed CAB Files for MFC and ATL Controls

If you plan to distribute MFC and ATL controls via the Internet, you should package them as signed Cabinet (CAB) files. Signed files assure a user downloading your control that the code is safe. A CAB file contains a compressed version of your control plus information about how your control is to be installed, for example, what DLLs need to be installed along with the OCX.

The tools you need to create and sign CAB files are provided on the Visual C++ CD in the CAB&SIGN directory. The utilities in the CAB&SIGN directory are not installed automatically when you install Visual C++, so you must copy the contents of the CAB&SIGN directory to your hard drive.

Before you can sign files, you need to get a Software Publisher Certificate. You must apply for your own certificate to a Certification Authority. With the tools in the CAB&SIGN directory you can create a test certificate for testing purposes, but this certificate cannot be used to sign code for distribution. See step 1 for information about applying for a Software Publisher Certificate.

These are the steps to create a signed CAB file:

  1. Get a Software Publisher Certificate (you only need to do this once)

  2. Create the CAB file

  3. Sign your files

  4. Embed the signed CAB file in a Web page (optional)


Getting a Software Publisher Certificate

Before you can sign files, you need to obtain a Software Publisher Certificate (SPC). To do this, you must make a request to a Certification Authority. During the application process, you must generate a key pair and provide the Certification Authority with identification information, such as your name, address, and public key. You must also make a legally binding pledge that you cannot and will not distribute software you know or should have known contains viruses or will otherwise maliciously harm the user's machine or code.

For more information about obtaining a Software Publisher Certificate (SPC), see http://www.microsoft.com/intdev/security/authcode/codesign.htm. To apply for a certificate, see http://www.microsoft.com/intdev/security/authcode/certs.htm. To create a test certificate to test signing your files, see Making a Test Software Publisher Certificate.

The Certification Authority generates a Software Publisher Certificate that conforms to the industry standard X.509 certificate format with Version 3 extensions. The certificate identifies you and contains your public key. It is stored by the Certification Authority for reference and a copy is returned to you via electronic mail. After accepting the certificate, you should include a copy in all published software signed with the private key.


Creating a CAB File

This section describes creating CAB files for distributing ATL and MFC controls over the Internet. If you need more information about CAB files, see the Cabinet File Reference in the Platform SDK section Setup and System Management Services\Setup API\Overview\Cabinet Files. The Platform SDK is included with the MSDN online documentation.

To create a CAB file:

  1. Create an INF file.

  2. Run the CABARC utility.


Signing a CAB File

To sign a CAB file using the Code Signing Wizard:

  1. Run the SIGNCODE utility (available in the CAB&SIGN directory on the Visual C++ CD) to launch the Code Signing Wizard.
    C:\CAB&SIGN\SIGNCODE
  2. In the Code Signing Wizard dialog box, click Next to advance to the next page.

  3. In the Which program would you like to sign? edit box, enter the name of the CAB file you want to sign.

  4. In the What would you like to call this program? edit box, enter the name as you want it to appear on the certificate.

  5. Click Next to advance to the next page.

  6. In the Under which Software Publishing Credentials would you like to sign this program? edit box, enter the name of the Software Publisher Certificate (SPC) file.

  7. In the Where can you find the secret, private key that goes with these credentials? edit box, enter the name of the private key (PVK) file.

  8. Click Next twice to advance to the last page.

  9. Click Sign to sign the CAB file. Your file will be digitally signed.

You can sign your DLLs and OCXs directly, without using a CAB file. The advantages of a CAB file are compression and, if used with an INF file, the bundling of all necessary code together.


Embedding a Signed CAB File on a Web Page

ATL and MFC controls are embedded in Web pages using the <OBJECT> tag. Within the <OBJECT> tag, you need to specify three attributes for the control:

  • ID The name of the control

  • CLASSID The CLSID of the control

  • CODEBASE The location from which to download the control. Note that CODEBASE can point at a number of different file types successfully.

As an example, the following Web page displays the ATL Polygon control archived in the CAB file created in the section on Creating an INF File. The address http://www.mysite.com/mydir/polygon.cab should be replaced with the actual HTTP address of the CAB file:

<HTML>
<HEAD>
<TITLE>ATL 2.0 test page for object PolyCtl</TITLE>
</HEAD>
<BODY>
<OBJECT ID="PolyCtl"
CLASSID="CLSID:4CBBC676-507F-11D0-B98B-000000000000"
CODEBASE="http://www.mysite.com/mydir/polygon.cab">
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
<!--
Sub PolyCtl_ClickIn(x, y)
PolyCtl.Sides = PolyCtl.Sides + 1
End Sub
Sub PolyCtl_ClickOut(x, y)
PolyCtl.Sides = PolyCtl.Sides - 1
End Sub
-->
</SCRIPT>
</BODY>
</HTML>

CODEBASE can point directly to an OCX or DLL file:

CODEBASE="http://www.mysite.com/mydir/polygon.dll#version=1,0,0,1"

Since this causes only the DLL or OCX file to be downloaded and installed, any necessary supporting DLLs must already be on the client machine.

If you include the optional version number with a CAB file, the version number should refer to the control being downloaded. For example, since POLYGON.DLL has a version number of 1, 0, 0, 1, the version for the CAB is also 1, 0, 0, 1:

CODEBASE="http://www.mysite.com/mydir/polygon.cab#version=1,0,0,1"

If you do not include the version number, older versions of the same control will not be replaced if they are found on the client machine.


Internet First Steps: Active Documents

Home | Overview | How Do I

This article includes details about the steps needed to add Active document object support to your application. There are several paths you can take, depending on the support for Active technology your application currently has.

Add Active Document Support to a New Application

In AppWizard, you can create a new application with Active document support by choosing Full Server, or Both Container and Server when asked to specify "What compound document support would you like to include?", and selecting the check box for Active document server.

Convert an Existing MFC In-Process Server to an Active Document Server

If your application was created with a version of Visual C++ prior to version 4.2 and is already an in-process server, you can add Active document support by making changes to the following classes:

Class type | Formerly derived from | Change to derive from
In-Place Frame | COleIPFrameWnd | COleDocIPFrameWnd
Item | COleServerItem | CDocObjectServerItem

You will also change how information is entered in the registry, and make several other changes. These changes are detailed in Upgrade to an Active Document Server.. If your application currently has no COM components support, you can add server support by running AppWizard and integrating the COM component-specific code with your existing application and then following the steps described in Upgrade to an Active Document Server.

Add Active Document Support to an Existing Application That Currently Has No Active Technology Support

You can follow the steps in the tutorial Creating an OLE Server, and then follow the steps described in Upgrade to an Active Document Server.

See Also Internet: Where Is..., Active Documents, BINDSCRB, Active Documents


Internet First Steps: Asynchronous Monikers

Home | Overview | How Do I

With asynchronous monikers, you can extend your COM application to download asynchronously across the Internet and to provide progressive rendering of large objects such as bitmaps and VRML objects. Asynchronous monikers enable an ActiveX control property or a file on the Internet to be downloaded without blocking the response of the user interface. For basic information about asynchronous moniker support, see Internet Downloading Using Asynchronous Monikers.

To download a file using asynchronous monikers

  1. Declare a class derived from CAsyncMonikerFile.

  2. Override OnDataAvailable to display the data

  3. Override other member functions, including OnProgress, OnStartBinding, and OnStopBinding.

  4. Declare an instance of this class and use it to open URLs.

For information about downloading asynchronously in an ActiveX control, see Internet First Steps: ActiveX Controls.

See Also Internet: Where Is...


Internet First Steps: ISAPI Server Extensions and Filters

Home | Overview | How Do I

If you already have an application and want to run it on a Web server, there are several tasks to complete:

  • Remove any dialog boxes and other user-interface features from the DLL that will run on the server.

  • When running on a Web server, you provide content to the client through HTML. Design the HTML pages you will use on the client to collect information that is sent to the server, and to return results to the client.

  • Reduce code size and remove unnecessary functions to increase processing efficiency.

  • If you are writing a database front-end application using simple queries, you may be able to use DB Connector (which ships as part of Internet Information Server) for your database processing. See the documentation that comes with Internet Information Server.

    If you want to use multiple queries on a page or use advanced features of SQL Server, you will need to write an ISAPI DLL to provide special forms processing and to access the full capabilities of SQL Server.

For more information on ISAPI, see:

  • ISAPI: Extending Web Servers

  • Steps to Create a Typical ISAPI Extension

  • Steps to Create a Typical ISAPI Filter

See Also Internet: Where Is..., ISAPI Server Extensions and Filters, Internet Server API (ISAPI) Extensions


Internet First Steps: WinInet

Home | Overview | How Do I

You can use WinInet to add FTP support to download and upload files from within your application. You can override OnStatusCallback and use the dwContext parameter to provide progress information to users as you search for and download files.

This article contains the following topics:

  • Create a Very Simple Browser

  • Download a Web Page

  • FTP a File

  • Retrieve a Gopher Directory

  • Display Progress Information While Transferring Files

The code excerpts below demonstrate how to create a simple browser, download a Web page, FTP a file, and search for a gopher file. They are not meant as complete examples and they do not contain exception handling. See the Internet samples, such as TEAR, for more complete examples.

Create a Very Simple Browser

#include <afxinet.h>
//assumes URL names have been initialized
CInternetSession session("My Session");
CStdioFile* pFile = NULL;
//use a URL and display a Web page
while (lpszURL = DisplayPage(...))
{
   pFile = session.OpenURL(lpszURL);
   while (pFile->Read(szBuff,1024) > 0)
   {
      //read file...
   }
   delete pFile;
}
session.Close();

Download a Web Page

//this code excerpt also demonstrates how to use //try/catch exception handling
#include <afxinet.h>
//assumes server, port and URL names have been initialized
CInternetSession session("My Session");
CHttpConnection* pServer = NULL;
CHttpFile* pFile = NULL;
try
{
   CString strServerName;
   INTERNET_PORT nPort;

   pServer = session.GetHttpConnection(strServerName, nPort);
   pFile = pServer->OpenRequest(CHttpConnection::HTTP_VERB_GET, strObject);
   pFile->AddRequestHeaders(szHeaders);
   pFile->SendRequest();
   pFile->QueryInfoStatusCode(dwRet);

   if (dwRet == HTTP_STATUS_OK)
   {
       UINT nRead = pFile->Read(szBuff, 1023);
       while (nRead > 0)
       {
           //read file...
       }
   }
   delete pFile;
   delete pServer;
}
catch (CInternetException* pEx)
{
   //catch errors from WinInet
}
session.Close();

FTP a File

#include <afxinet.h>
//assumes server and file names have been initialized
CInternetSession session("My FTP Session");
CFtpConnection* pConn = NULL;

pConn = session.GetFtpConnection(lpszServerName);
//get the file
if (!pConn->GetFile(pstrRemoteFile, pstrLocalFile))
   //display an error
delete pConn;
session.Close();

Retrieve a Gopher Directory

#include <afxinet.h>
//assumes file name has been initialized
CInternetSession session("My Gopher Session");
CGopherConnection* pConn = NULL;
CGopherFileFind* pFile;

pConn = session.GetGopherConnection("gopher.yoursite.com");
pFile = new CGopherFileFind(pConn);
BOOL bFound = pFile->FindFile(lpszFileToFind);
while (bFound)
{
   bFound = pFile->FindNextFile();
   //retrieve attributes of found file
}
delete pFile;
delete pConn;
session.Close();

Use OnStatusCallback

When using the WinInet classes, you can use the OnStatusCallback member of your application's CInternetSession object to retrieve status information. If you derive your own CInternetSession object, override OnStatusCallback, and enable status callbacks, MFC will call your OnStatusCallback function with progress information about all the activity in that Internet session.

Because a single session might support several connections (which, over their lifetime, might perform many different distinct operations), OnStatusCallback needs a mechanism to identify each status change with a particular connection or transaction. That mechanism is provided by the context ID parameter given to many of the member functions in the WinInet support classes. This parameter is always of type DWORD and is always named dwContext.

The context assigned to a particular Internet object is used only to identify the activity the object causes in the OnStatusCallback member of the CInternetSession object. The call to OnStatusCallback receives several parameters; these parameters work together to tell your application what progress has been made for which transaction and connection.

When you create a CInternetSession object, you can specify a dwContext parameter to the constructor. CInternetSession itself doesn't use the context ID; instead, it passes the context ID on to any InternetConnection-derived objects that don't explicitly get a context ID of their own. In turn, those CInternetConnection objects will pass the context ID along to CInternetFile objects they create if you don't explicitly specify a different context ID. If, on the other hand, you do specify a specific context ID of your own, the object and any work it does will be associated with that context ID. You can use the context IDs to identify what status information is being given to you in your OnStatusCallback function.

Display Progress Information While Transferring Files

For example, if you write an application that creates a connection with an FTP server to read a file and also connects to an HTTP server to get a Web page, you'll have a CInternetSession object, two CInternetConnection objects (one would be a CFtpSession and the other would be a CHttpSession), and two CInternetFile objects (one for each connection). If you used default values for the dwContext parameters, you would not be able to distinguish between the OnStatusCallback invocations that indicate progress for the FTP connection and the invocations that indicate progress for the HTTP connection. If you specify a dwContext ID, which you can later test for in OnStatusCallback, you will know which operation generated the callback.

See Also Internet: Where Is..., Internet Programming with WinInet, WinInet (HTTP, FTP, gopher)


Internet First Steps: Testing

Home | Overview | How Do I

There are some unique testing challenges on the Internet, especially for applications running on a Web server. Your initial testing for your ISAPI extension or filter will probably be done using a single-user client connecting to a test server. This will be useful for debugging your code.

You will also want to test under real conditions: with multiple clients connected over high-speed connections as well as low-speed serial lines, including modem connections. It can be difficult to simulate real conditions, but it is certainly worth spending time designing possible scenarios and executing them. If possible, you will also want to use tools to do capacity and stress testing. Certain classes of bugs, such as timing bugs, are difficult to find and to reproduce.

One of the challenges of Internet programming is its visibility. Many accesses to your site may slow down your server. You want your server to degrade gracefully. You want to prevent anything that could be destructive to a user's computer if your application fails (for example, corruption of data while writing to the registry or while writing cookies on the client).

See Also Internet: Where Is...


Internet First Steps: Security

Home | Overview | How Do I

Code safety is a major issue for developers and for users of Internet applications. There are risks: malicious code, code that has been tampered with, and code from unknown sites or authors.

There are two basic approaches to security when developing for the Internet. The first is called "sandboxing." In this approach, an application is restricted to a particular set of APIs, and excluded from potentially dangerous ones such as file I/O where a program could destroy data on a user's computer. The second is implemented using digital signatures. This approach is referred to as "shrinkwrap" for the Internet. Code is verified and signed using private key/public key technology. Before the code is run, its digital signature is verified to ensure that the code is from a known authenticated source, and that the code has not been altered since it has been signed.

In the first case, you trust that the application will not do any harm and you trust the origin of the application. In the second, digital signatures are used to verify authenticity. Digital signing is an industry standard used to identify and provide details about the publisher of the code. Its technology is based on standards including RSA and X.509. Browsers typically allow users to choose if they want to download and run code of unknown origin.

Additional information about code signing and other security measures is available on the Web. Information can be accessed through the Microsoft Developer Network Online site at http://www.microsoft.com/msdn, or through the World Wide Web consortium at http://www.w3.org/pub.

See Also Internet: Where Is...


Internet First Steps: HTML

Home | Overview | How Do I

Most browsers have the capability of examining the HTML source of the pages you browse. When you view the source you will see a number of HTML (Hypertext markup language) tags, surrounded by angle brackets(<>), interspersed with text.

The steps below use HTML tags to build a simple Web page. In these steps, you'll type plain text into a file in Notepad, make a few changes, save the file, and reload your page in the browser to see your changes.

To create an HTML file

  1. Open Notepad or any plain text editor.

  2. From the File menu, choose New.

  3. Type the following lines:
    <HTML>
<HEAD>
<TITLE>Top HTML Tags</TITLE>
</HEAD>
</HTML>
  4. From the File menu, choose Save, and name the file First.htm. Leave the file open in the editor.

  5. Switch to your browser, and from the File menu, choose Open, or type file://C:/webpages/first.htm in the browser's URL edit box. You should see a blank page with the window caption "Top HTML Tags."

    Notice the tags are paired and are included in angle brackets. Tags are not case-sensitive, but capitalization is often used to make tags stand out.

    The tag <HTML> starts the document, and the tag </HTML> ends it. Ending tags (not always required) are the same as the starting tag, but have a forward slash (/) in front of the tag. There should be no spaces between the angle bracket (<) and the start of your tag.

  6. Switch back to Notepad, and after the </HEAD> line, type:
    <BODY>
HTML is swell.
Life is good.
</BODY>
  7. From the File menu, choose Save.

  8. Switch back to your browser and refresh the page.

    The words will appear in the client area of your browser's window. Notice that your carriage return is ignored. If you want to have a line break, you must include a <BR> tag after the first line.

    For all the steps that follow, insert the text anywhere between <BODY> and </BODY> to add to the body of your document.

  9. Add a header:
    <H3>Here's the big picture</H3>
  10. Add an image, using a .gif file saved in the same directory as your page:
    <IMG src="yourfile.gif">
  11. Add a list:
    <UL>Make me an unordered list.
<LI>One programmer</LI>
<LI>Ten SDKs</LI>
<LI>Great Internet Apps</LI>
</UL>
  12. To number the list instead, use paired <OL> and </OL> tags in place of the <UL> and </UL> tags.

That should get you started. If you see a great feature on a Web page, you can find out how it was created by examining the HTML source. HTML editors such as Microsoft Front Page can be used to create both simple and advanced pages.

Here's the entire HTML source for the file you've been building:

<HTML>
<HEAD>
<TITLE>Top HTML Tags</TITLE>
</HEAD>
<BODY>
HTML is swell.<BR>
Life is good.
<H3>Here's the big picture</H3>
<IMG src="yourfile.gif">
<UL>Make me an unordered list.
<LI>One programmer</LI>
<LI>Ten SDKs</LI>
<LI>Great Internet Apps</LI>
</UL>
</BODY>
</HTML>

For a complete description of tags, attributes, and extensions, see the Hypertext Markup Language (HTML) specification:

http://www.w3.org/pub/WWW/MarkUp/

There is a W3C working draft currently under review for the object tag, an extension to HTML to include dynamic content on a Web page. A list of current W3C working drafts, including this one, can be found at:

http://www.w3.org/pub/WWW/TR

See Also Internet: Where Is...


Internet First Steps: HTTP

Home | Overview | How Do I

When writing an ISAPI application, you often examine and add to the information in HTTP header. Return codes indicate the success or failure of the requested event. Several common return codes are listed in the following table.

Return Code | Meaning
200 | URL located, transmission follows
400 | Unintelligible request
404 | Requested URL not found
405 | Server does not support requested method
500 | Unknown server error
503 | Service unavailable

Additional return codes can be found in the AFXISAPI.H file. The HTTP responses are grouped as shown in the following table.

Group | Meaning
200–299 | Success
300–399 | Information
400–499 | Request error
500–599 | Server error

The Hypertext Transfer Protocol (HTTP) is an application-level protocol for hypermedia information systems. For additional information about HTTP, and how Web browsers and servers communicate, see the Hypertext Transfer Protocol (HTTP) specification:

http://www.w3.org/pub/WWW/Protocols/

See Also Internet: Where Is...


Internet Programming with WinInet

Home | Overview | How Do I

An Internet client application is a program that accesses information from a network data source (server) using Internet protocols such as gopher, FTP, or HTTP. An Internet client application might access a server to retrieve data such as weather maps, stock prices, or newspaper headlines, for example. The Internet client can access the server through an external network (the Internet) or an internal network (sometimes called an intranet).

MFC includes the Win32 Internet Extensions, or WinInet, for creating an Internet client application. MFC encapsulates these Internet extensions in a set of standard, easy-to-use classes. You can write a WinInet client application by calling the Win32 functions directly or by using the MFC WinInet classes.

If you want to write an Internet server application, use the MFC Internet Server API (ISAPI) extensions.

The following topics discuss the process of creating an Internet client application:

  • How WinInet Makes It Easier to Create Internet Client Applications

  • How MFC Makes It Easier to Create Internet Client Applications

  • MFC Classes for Creating Internet Client Applications

  • Prerequisites for Internet Client Classes

  • Writing an Internet Client Application Using MFC WinInet Classes

The following topics provide steps for performing typical WinInet tasks:

  • Steps in a Typical Internet Client Application

  • Steps in a Typical FTP Client Application

  • Steps in a Typical FTP Client Application to Delete a File

  • Steps in a Typical Gopher Client Application

  • Steps in a Typical HTTP Client Application

See Also Internet: Where Is..., WinInet (HTTP, FTP, gopher), Internet First Steps: WinInet


How WinInet Makes It Easier to Create Internet Client Applications

Home | Overview | How Do I

The Win32 Internet Extensions, or WinInet, provide access to common Internet protocols, including gopher, FTP, and HTTP. Using WinInet, you can write Internet client applications at a higher level of programming, without having to deal with WinSock, TCP/IP, or the details of specific Internet protocols. WinInet provides a consistent set of functions for all three protocols, with a familiar Win32 API interface. This consistency minimizes code changes you need to make if the underlying protocol changes (for example, from FTP to HTTP).

Visual C++ provides two ways for you to use WinInet. You can call the Win32 Internet functions directly (see the OLE documentation in the Win32 SDK for more information) or you can use WinInet through the MFC WinInet classes.


How MFC Makes It Easier to Create Internet Client Applications

Home | Overview | How Do I

The Microsoft Foundation Classes encapsulate the Win32 Internet Extension (WinInet) functions in a manner that provides a familiar context for MFC programmers. MFC provides three Internet file classes (CInternetFile, CHttpFile, and CGopherFile) derived from the CStdioFile class. Not only do these classes make retrieving and manipulating Internet data familiar to programmers who have used CStdioFile for local files, but with these classes you can handle local files and Internet files in a consistent, transparent manner.

In addition, the MFC WinInet classes provide the following advantages:

  • Buffered I/O

  • Type-safe handles for your data

  • Default parameters for many functions

  • Exception handling for common Internet errors

  • Automatic cleanup of open handles and connections


MFC Classes for Creating Internet Client Applications

Home | Overview | How Do I

MFC provides the following classes and global functions for writing Internet client applications. Indentation indicates a class is derived from the unindented class above it. CGopherFile and CHttpFile derive from CInternetFile, for example.

Classes:

CInternetSession

CInternetConnection

CFtpConnection

CGopherConnection

CHttpConnection

CInternetFile

CGopherFile

CHttpFile

CFileFind

CFtpFileFind

CGopherFileFind

CGopherLocator

CInternetException

Global functions:

AfxParseURL

AfxGetInternetHandleType

AfxThrowInternetException

These classes and global functions are declared in AFXINET.H, except CFileFind, which is declared in AFX.H.


Prerequisites for Internet Client Classes

Home | Overview | How Do I

Some actions taken by an Internet client (reading a file, for example) have prerequisite actions (in this case, establishing an Internet connection). The following tables list the prerequisites for some client actions.

General Internet URL (FTP, Gopher, or HTTP)

Action | Prerequisite
Establish a connection. | Create a CInternetSession to establish the basis of an Internet client application.
Open a URL. Establish a connection.
Call CInternetSession::OpenURL.
The OpenURL function returns a read-only resource object.
Read URL data. Open the URL.
Call CInternetFile::Read.
Query the setting of an Internet option. Establish a connection.
Call CInternetSession::QueryOption.
Set an Internet option. Establish a connection.
Call CInternetSession::SetOption.
Set a function to be called with status information. Establish a connection.
Call CInternetSession::EnableStatusCallback.
Override CInternetSession::OnStatusCallback to handle calls.

FTP

Action | Prerequisite
Establish an FTP connection. | Create a CInternetSession as the basis of this Internet client application. Call CInternetSession::GetFtpConnection to create a CFtpConnection object.
Find the first resource. | Establish an FTP connection. Create a CFtpFileFind object. Call CFtpFileFind::FindFile.
Enumerate all available resources. | Find the first file. Call CFtpFileFind::FindNextFile until it returns FALSE.
Open an FTP file. | Establish an FTP connection. Call CFtpConnection::OpenFile to create and open a CInternetFile object.
Read an FTP file. | Open an FTP file with read access. Call CInternetFile::Read.
Write to an FTP file. | Open an FTP file with write access. Call CInternetFile::Write.
Change the client's directory on the server. | Establish an FTP connection. Call CFtpConnection::SetCurrentDirectory.
Retrieve the client's current directory on the server. | Establish an FTP connection. Call CFtpConnection::GetCurrentDirectory.

HTTP

Action Prerequisite
Establish an HTTP connection. Create a CInternetSession as the basis of this Internet client application.
Call CInternetSession::
GetHttpConnection to create a CHttpConnection object.
Open an HTTP file. Establish an HTTP connection.
Call CHttpConnection::OpenRequest to create a CHttpFile object.
Call CHttpFile::AddRequestHeaders.
Call CHttpFile::SendRequest.
Read an HTTP file. Open an HTTP file.
Call CInternetFile::Read.
Get information about an HTTP request. Establish an HTTP connection.
Call CHttpConnection::OpenRequest to create a CHttpFile object.
Call CHttpFile::QueryInfo.

Gopher

Action Prerequisite
Establish a gopher connection. Create a CInternetSession as the basis of this Internet client application.
Call CInternetSession::
GetGopherConnection to create a CGopherConnection.
Find the first file in the current directory. Establish a gopher connection.
Create a CGopherFileFind object.
Call CGopherConnection::
CreateLocator to create a CGopherLocator object.
Pass the locator to CGopherFileFind::FindFile.
Call CGopherFileFind::GetLocator to get the locator of a file if you need it later.
Enumerate all available files. Find the first file.
Call CGopherFileFind::FindNextFile until it returns FALSE.
Open a gopher file. Establish a gopher connection.
Create a gopher locator with CGopherConnection::CreateLocator or find a locator with CGopherFileFind::GetLocator.
Call CGopherConnection::OpenFile.
Read a gopher file. Open a gopher file.
Use CGopherFile.


Writing an Internet Client Application Using MFC WinInet Classes

Home | Overview | How Do I

The basis of every Internet client application is the Internet session. MFC implements Internet sessions as objects of class CInternetSession. Using this class, you can create one Internet session or several simultaneous sessions.

To communicate with a server, you need a CInternetConnection object as well as a CInternetSession. You can create a CInternetConnection by using CInternetSession::GetFtpConnection, CInternetSession::GetHttpConnection, or CInternetSession::GetGopherConnection. Each of these calls is specific to the protocol type. These calls do not open a file on the server for reading or writing. If you intend to read or write data, you must open the file as a separate step.

For most Internet sessions, the CInternetSession object works hand-in-hand with a CInternetFile object:

  • For an Internet session, you must create an instance of CInternetSession.

  • If your Internet session reads or writes data, you must create an instance of CInternetFile (or its subclasses, CHttpFile or CGopherFile). The easiest way to read data is to call CInternetSession::OpenURL. This function parses a Universal Resource Locator (URL) supplied by you, opens a connection to the server specified by the URL, and returns a read-only CInternetFile object. CInternetSession::OpenURL is not specific to one protocol type ? the same call works for any FTP, HTTP, or gopher URL. CInternetSession::OpenURL even works with local files (returning a CStdioFile instead of a CInternetFile).

  • If your Internet session does not read or write data, but performs other tasks, such as deleting a file in an FTP directory, you may not need to create an instance of CInternetFile.

There are two ways to create a CInternetFile object:

  • If you use CInternetSession::OpenURL to establish your server connection, the call to OpenURL returns a CInternetFile.

  • If use CInternetSession::GetFtpConnection, GetGopherConnection, or GetHttpConnection to establish your server connection, you must call CFtpConnection::OpenFile, CGopherConnection::OpenFile, or CHttpConnection::OpenRequest, respectively, to return a CInternetFile, CGopherFile, or CHttpFile, respectively.

The steps in implementing an Internet client application vary depending on whether you create a generic Internet client based on OpenURL or a protocol-specific client using one of the GetConnection functions.

What do you know more about?

  • How do I write an Internet client application that works generically with FTP, HTTP, and gopher?

  • How do I write an FTP client application that opens a file?

  • How do I write an FTP client application that does not open a file but performs a directory operation, such as deleting a file?

  • How do I write a gopher client application?

  • How do I write an HTTP client application?


Steps in a Typical Internet Client Application

Home | Overview | How Do I

The following table shows the steps you might perform in a typical Internet client application.

Your goal | Actions you take | Effects
Begin an Internet session. | Create a CInternetSession object. | Initializes WinInet and connects to server.
Read or set an Internet query option (time-out limit or number of retries, for example). Use CInternetSession::
QueryOption or CInternetSession::
SetOption. 		Returns FALSE if operation was unsuccessful.
Establish a callback function to monitor the status of the session. Use CInternetSession::
EnableStatusCallback. 		Establishes a callback to CInternetSession::
OnStatusCallback. Override OnStatusCallback to create your own callback routine.
Connect to an Internet server, intranet server, or local file. Use CInternetSession::
OpenURL. 		Parses the URL and opens a connection to the specified server. Returns a CStdioFile (if you pass OpenURL a local file name) or a CInternetFile. This is the object through which you access data retrieved from the server or file.
Read from the file. | Use CInternetFile::Read. | Reads the specified number of bytes using a buffer you supply.
Handle exceptions. | Use the CInternetException class. | Handles all common Internet exception types.
End the Internet session. | Dispose of the CInternetSession object. | Automatically cleans up open file handles and connections.

See Also Prerequisites for Internet Client Classes


Steps in a Typical FTP Client Application

Home | Overview | How Do I

A sample FTP client application is available. FTPTREE is a dialog-based application that displays the contents of an FTP site in a tree control.

The following table shows the steps you might perform in a typical FTP client application.

Your goal | Actions you take | Effects
Begin an FTP session. | Create a CInternetSession object. | Initializes WinInet and connects to server.
Connect to an FTP server. | Use CInternetSession:: GetFtpConnection. | Returns a CFtpConnection object.
Change to a new FTP directory on the server. | Use CFtpConnection:: SetCurrentDirectory. | Changes the directory you are currently connected to on the server.
Find the first file in the FTP directory. | Use CFtpFileFind::FindFile. | Finds the first file. Returns FALSE if no files are found.
Find the next file in the FTP directory. | Use CFtpFileFind::FindNextFile. | Finds the next file. Returns FALSE if the file is not found.
Open the file found by FindFile or FindNextFile for reading or writing. | Use CFtpConnection::OpenFile, using the file name returned by FindFile or FindNextFile. | Opens the file on the server for reading or writing. Returns a CInternetFile object.
Read from or write to the file. | Use CInternetFile::Read or CInternetFile::Write. | Reads or writes the specified number of bytes, using a buffer you supply.
Handle exceptions. | Use the CInternetException class. | Handles all common Internet exception types.
End the FTP session. | Dispose of the CInternetSession object. | Automatically cleans up open file handles and connections.

See Also Prerequisites for Internet Client Classes


Steps in a Typical FTP Client Application to Delete a File

Home | Overview | How Do I

The following table shows the steps you might perform in a typical FTP client application that deletes a file.

Your goal | Actions you take | Effects
Begin an FTP session. | Create a CInternetSession object. | Initializes WinInet and connects to server.
Connect to an FTP server. Use CInternetSession::
GetFtpConnection. 		Returns a CFtpConnection object.
Check to make sure you’re in the right directory on the FTP server. Use CFtpConnection::
GetCurrentDirectory or CFtpConnection::
GetCurrentDirectoryAsURL. 		Returns the name or URL of the directory you are currently connected to on the server, depending on the member function selected.
Change to a new FTP directory on the server. Use CFtpConnection::
SetCurrentDirectory. 		Changes the directory you are currently connected to on the server.
Find the first file in the FTP directory. | Use CFtpFileFind::FindFile. | Finds the first file. Returns FALSE if no files are found.
Find the next file in the FTP directory. Use CFtpFileFind::
FindNextFile. 		Finds the next file. Returns FALSE if the file is not found.
Delete the file found by FindFile or FindNextFile. | Use CFtpConnection::Remove, using the file name returned by FindFile or FindNextFile. | Deletes the file on the server for reading or writing.
Handle exceptions. | Use the CInternetException class. | Handles all common Internet exception types.
End the FTP session. | Dispose of the CInternetSession object. | Automatically cleans up open file handles and connections.

See Also Prerequisites for Internet Client Classes


Steps in a Typical Gopher Client Application

Home | Overview | How Do I

The following table shows the steps you might perform in a typical gopher client application.

Your goal | Actions you take | Effects
Begin a gopher session. | Create a CInternetSession object. | Initializes WinInet and connects to server.
Connect to a gopher server. Use CInternetSession::
GetGopherConnection. 		Returns a CGopherConnection object.
Find the first resource in the gopher. | Use CGopherFileFind::FindFile. | Finds the first file. Returns FALSE if no files are found.
Find the next resource in the gopher. | Use CGopherFileFind::FindNextFile. | Finds the next file. Returns FALSE if the file is not found.
Open the file found by FindFile or FindNextFile for reading. | Get a gopher locator using CGopherFileFind::GetLocator. Use CGopherConnection::OpenFile. | Opens the file specified by the locator. OpenFile returns a CGopherFile object.
Open a file using a gopher locator you supply. Create a gopher locator, using CGopherConnection::
CreateLocator. Use CGopherConnection::
OpenFile. 		Opens the file specified by the locator. OpenFile returns a CGopherFile object.
Read from the file. | Use CGopherFile. | Reads the specified number of bytes, using a buffer you supply.
Handle exceptions. | Use the CInternetException class. | Handles all common Internet exception types.
End the gopher session. | Dispose of the CInternetSession object. | Automatically cleans up open file handles and connections.

See Also Prerequisites for Internet Client Classes


Steps in a Typical HTTP Client Application

Home | Overview | How Do I

The following table shows the steps you might perform in a typical HTTP client application:

Your goal | Actions you take | Effects
Begin an HTTP session. | Create a CInternetSession object. | Initializes WinInet and connects to server.
Connect to an HTTP server. | Use CInternetSession:: GetHttpConnection. | Returns a CHttpConnection object.
Open an HTTP request. | Use CHttpConnection::OpenRequest. | Returns a CHttpFile object.
Send an HTTP request. | Use CHttpFile::AddRequestHeaders and CHttpFile::SendRequest. | Finds the file. Returns FALSE if the file is not found.
Read from the file. | Use CHttpFile. | Reads the specified number of bytes using a buffer you supply.
Handle exceptions. | Use the CInternetException class. | Handles all common Internet exception types.
End the HTTP session. | Dispose of the CInternetSession object. | Automatically cleans up open file handles and connections.

See Also Prerequisites for Internet Client Classes


Internet Server API (ISAPI) Extensions

Home | Overview | How Do I

This family of articles provides an overview on the Internet server extensions and filters you can write using MFC. ISAPI, the Internet Server Application Programming Interface, is a set of APIs used to write OLE Server extensions and filters for Web servers like Internet Information Server. MFC provides five classes that wrap ISAPI. Topics included in this article are:

  • What Is an Internet Server Extension?

  • What Is an ISAPI Filter?

  • What Kind of HTTP Server Is Needed to Run ISAPI?

  • ISAPI Samples

What Is an Internet Server Extension?

An ISAPI server extension is a DLL that can be loaded and called by an HTTP server. Internet server extensions, also known as Internet server applications (ISAs), are used to enhance the capabilities of an Internet Server API (ISAPI)-compliant server. An ISA is invoked from a browser application and provides similar functionality to a Common Gateway Interface (CGI) application. For more information, see the articles ISAPI: Extending Web Servers and ISAPI Extensions: Servers.

What Is an ISAPI Filter?

An ISAPI filter is a DLL that runs on an ISAPI-enabled HTTP server to filter data traveling to and from the server. The filter registers for notification of events, such as logging on or URL mapping. When the selected events occur, the filter is called, and you can monitor and change the data (on its way from the server to the client or vice versa). ISAPI filters can be used to provide enhanced logging of HTTP requests (for example, to track who is logging on to your server), custom encryption, custom compression, or additional authentication methods. For more information, see ISAPI Extensions: Filters.

What Kind of HTTP Server Is Needed to Run ISAPI?

To host Web sites, you must have an Internet server that supports the Hypertext Transfer Protocol (HTTP). If you have chosen an ISAPI-compliant Web server (for example, Microsoft Internet Information Server), you can take advantage of server extension DLLs to create small, fast Internet server applications.

Further Reading

For general information about ISAPI programming, see:

  • ISAPI: Extending Web Servers

  • ISAPI Extensions: MFC Classes

For more information about ISAPI server extensions, see:

  • ISAPI Extensions: Servers

  • ISAPI Extensions: Parse Maps

  • Steps to Create a Typical ISAPI Extension

For information about ISAPI filters, see:

  • ISAPI Extensions: Filters

  • Steps to Create a Typical ISAPI Filter

For tips about ISAPI programming, see:

  • ISAPI Programming Tips

  • ISAPI: Debugging

  • ISAPI and Databases

  • ISAPI: Getting More Information

See Also CHttpServer, CHttpServerContext, CHttpFilter, CHttpFilterContext, CHtmlStream, Internet: Where Is...


ISAPI: Extending Web Servers

Home | Overview | How Do I

This article describes some of the tasks you can perform with ISAPI Web server extensions, and how MFC supports writing them. Topics included in this article are:

  • How Does ISAPI Make it Easier to Create Internet Server Applications?

  • Advantages of Using MFC to Create Internet Server Applications

  • What Can I Do With ISAPI?

How Does ISAPI Make it Easier to Create Internet Server Applications?

You can use ISAPI to write database applications, such as an order entry system or a custom catalog. You can collect information from a user with an HTML form, and send back another HTML page customized for the user. ISAPI server extensions provide similar functionality to CGI applications. For a comparison of the two methods, see How Does ISAPI Compare with CGI?

A convenient feature of the World Wide Web is that you don't have to install your code on the client machine to run your application. This makes upgrading easy. To run an ISAPI server extension DLL, a user types a URL in a browser, for example, http://myserver/register.dll?. The DLL runs on the server and sends the HTML data back to the client.

To add an updated DLL with new features, you stop the Web server service, replace the old DLL with your new version in its shared location on the server, and restart the service. The next client request will load the latest version. This process makes it easy to add new functionality, and you upgrade only one computer instead of many.

Advantages of Using MFC to Create Internet Server Applications

Visual C++ includes the ISAPI Extension Wizard to help you create ISAPI filters and servers. This wizard is one of the choices available on the Project tab in the New dialog box, which appears when you create a new project in the development environment. For more information about establishing a new project using wizards, see Visual C++ Wizards that Help You Begin Your Program.

The ISAPI Extension Wizard makes it simple to generate a filter or a server extension. You can choose how (or if) to link to MFC; whether to have a filter, a server, or both; what filter notifications to handle at what priority; and whether the filter should get secured or unsecured notifications or both. After the project is generated, you add custom functionality and create parse maps.

Error Handling

MFC adds failure protection beyond any provided by the server. MFC handles the returning of appropriate HTTP errors to the client (for example, bad request). For a list of some common HTTP return codes, see Internet First Steps: HTTP. To handle error conditions in your program, see CHttpServer::OnParseError.

Forms Processing and Parse Maps

HTML-based forms are used to collect information from the user. This information is sent to your server via a URL that includes the name of your ISAPI DLL and a list of parameters, based on the information the user entered in the form. MFC makes parsing of these parameters easy: You write the function, declare its parameters, and use parse map macros to hook the command line arguments to your function parameters, including optional and default arguments. When a client invokes your server, MFC extracts the arguments and calls your function. MFC also returns results back to the client.

What Can I Do With ISAPI?

The following table lists some tasks you can perform using ISAPI server extensions and ISAPI filters.

I want to: | Use a server extension to:
Count users of my application. | Log information.
Write an order entry system. | Process an HTML form that is filled out at the client and processed on the server. Consider using DB Connector, a part of Internet Information Server, for simple data processing, and ISAPI for full database access.

I want to: | Use a filter to:
Count visitors to my server. | Request SF_NOTIFY_LOG notification.
Do custom encryption. | SF_NOTIFY_READ_RAW_DATA, SF_NOTIFY_WRITE_RAW_DATA
Do custom compression. | SF_NOTIFY_READ_RAW_DATA, SF_NOTIFY_WRITE_RAW_DATA
Read raw data. | SF_NOTIFY_READ_RAW_DATA
Process header information. | Call GetServerVariable.
Authenticate a user. | Create a filter with high priority notification request, SF_NOTIFY_AUTHENTICATION.
Log requests from a certain user, or requests containing key words. | Request SF_NOTIFY_URL_MAP notification.

See Also Internet: Where Is...


ISAPI Extensions: MFC Classes

Home | Overview | How Do I

This article describes the MFC classes that wrap the Internet Server API (ISAPI). If your Internet server software is ISAPI-compliant, you can create Internet server extensions and filters with MFC. MFC provides five classes that wrap ISAPI to create and handle Internet server extensions and filters:

  • CHttpServer An object to create and manage a server extension DLL, also known as an Internet server application (ISA). The ISA communicates with the server by means of the EXTENSION_CONTROL_BLOCK structure to handle client commands. Each client command corresponds to a member function of the CHttpServer object. The commands are parsed by the server’s parse map macros. Only one CHttpServer object can exist for each DLL. This object contains the EXTENSION_CONTROL_BLOCK provided by the server. A new CHttpServerContext object is created for each separate client request.

  • CHttpServerContext An object created by the CHttpServer object to handle a single request from a single client to the server object. Because the server may be handling concurrent, multiple requests, more than one active CHttpServerContext object can be associated with a particular CHttpServer instance.

  • CHtmlStream An object created by the CHttpServer object to manage a buffer for responding to the client. CHtmlStream can contain begin, end, and content HTML tags to format the response.

  • CHttpFilter An object you create to manage notification filters for incoming and outgoing client data. Like a CHttpServer object, only one CHttpFilter object can exist per DLL. When the CHttpFilter object is constructed, it creates a CHttpFilterContext object to manage a single notification from a single client. Because the server on which the filter is active may be handling concurrent, multiple requests, more than one active CHttpFilterContext object can be associated with a particular CHttpFilter instance.

  • CHttpFilterContext An object created by the CHttpFilter object to handle a single notification for a single client.

CHttpServer and CHttpFilter can exist independently of each other; that is, you do not have to use a CHttpFilter with your CHttpServer, and vice versa. It is also possible for one of each to be in a single DLL.

See Also Internet: Where Is...


ISAPI Extensions: Filters

Home | Overview | How Do I

This article describes the benefits of ISAPI filters and how to use them with Internet servers. Topics included in this article are:

  • How ISAPI Filters Can Enhance a Server

  • Filter Entry-Point Functions

  • Types of Filter Notifications

The development environment includes an ISAPI Extension Wizard to help you create an ISAPI filter and set the appropriate notifications. For information on using the wizard, see the article Steps to Create a Typical ISAPI Filter.

See the MFC Internet sample MFCUCASE for an illustration of how to use a CHttpFilter object to create a filter that converts content to uppercase by overriding two CHttpFilter member functions: OnSendRawData and OnUrlMap.

How Filters Can Enhance a Server

Use Internet Server API (ISAPI) filters to enhance Internet servers with custom features such as enhanced logging of HTTP requests, custom encryption and compression schemes, or new authentication methods. The filter application sits between the network connection to the clients and the HTTP server. Depending on the options that the filter application requests notification for, it can act on several server actions. Filters can be set to receive notification when selected events occur, including reading raw data from the client, processing the headers, managing communications over a secure port using Personal Communications Technology (PCT) or Secure Sockets Layer (SSL), or handling other stages in the processing of the HTTP request.

Filter Entry-Point Functions

Use the MFC class CHttpFilter to create a filter to manage the incoming and outgoing data for an ISAPI server. Two entry-point member functions, CHttpFilter::GetFilterVersion and CHttpFilter::HttpFilterProc, establish the filter and configure it for the notifications it will act upon.

GetFilterVersion

Using CHttpFilter requires that the filter application's path be inserted into the registry, in HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W3SVC/Parameters/FilterDLLs. When the server starts up, it reads this value and loads the DLLs listed. It then calls CHttpFilter::GetFilterVersion to perform three tasks:

  • Exchange version information

    The MFC implementation of GetFilterVersion compares the version number for which you are creating your filter with the server’s version number.

  • Determine the requested events

    Register your ISAPI filter applications only for the events that you require. If you register for extraneous events, your choices can have a significant negative impact on the performance and scalability of your filter.

  • Specify the priority to deliver the requested events

    The priority of requested events is specified by GetFilterVersion in the dwFlags member of the HTTP_FILTER_VERSION structure. After the GetFilterVersion exchange, every time the server processes one of the events, it will call any filters that have registered for that event. The calling order depends on priority.

HttpFilterProc

The second CHttpFilter member function to consider as an entry point is CHttpFilter::HttpFilterProc. As events happen, the server notifies each filter that registered for the event by calling the filter’s HttpFilterProc entry point. MFC's implementation of CHttpFilter::HttpFilterProc determines which event was fired and calls one of the CHttpFilter members dedicated to handling the specific notification. You can override HttpFilterProc to provide special handling for events. To write code that reacts only to a particular event, see the next section, Types of Filter Notifications.

Types of Filter Notifications

When CHttpFilter::HttpFilterProc is called, the notifications received will determine which of the CHttpFilter member functions will be called. In your override of an individual HttpFilterProc member function, you can set the filter object to change data in a specific manner. For example, you can create an encryption or compression filter by overriding OnSendRawData and providing whatever special functionality your filter needs. Other overridable member functions include:

  • OnPreprocHeaders Notifies the filter that the server has preprocessed the client headers.

  • OnAuthentication Authenticates the client.

  • OnUrlMap Notifies a filter when a server is mapping a logical URL to a physical path.

  • OnSendRawData Notifies the filter before raw data is sent from the server to the client.

  • OnReadRawData Notifies the filter after raw data is sent from the client to the server, but before the server processes it.

  • OnLog Logs information to a server file.

  • OnEndOfNetSession Notifies the filter that the session is ending.

See Also CHttpFilter, CHttpFilterContext, Internet: Where Is...


Steps to Create a Typical ISAPI Filter

Home | Overview | How Do I

Once you are familiar with the benefits of ISAPI filters and how to use them, you can create a filter project using the ISAPI Extension Wizard. For more information about starting a new project using wizards, see Visual C++ Wizards that Help You Begin Your Program. After the project has been created, you add your custom notification handlers. The steps are described below.

To create your project using the ISAPI Extension Wizard

  1. In the development environment, choose New from the File menu, and click the Projects tab.

  2. On the Projects tab, click ISAPI Extension Wizard and name your project.

  3. In Step 1 of the ISAPI Extension Wizard, check the option to Generate a Filter object.

  4. Name your CHttpFilter object, and choose whether to link to the MFC DLLs statically or dynamically, then choose the Next button.

    Feature Only in Professional and Enterprise Edition Static linking to MFC is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

  5. In Step 2 of the ISAPI Extension Wizard, select a filter notification priority.

    The default notification priority, which is recommended, is Low. Other priority notifications can affect performance and scalability.

  6. Choose which type of connections cause notifications for the filter.

    The filter can receive notifications from a secured port, a nonsecured port, or both. The ISAPI Extension Wizard sets both as the default.

  7. Choose what notifications your filter will process.

    See CHttpFilter::GetFilterVersion for a description of the notification flags and CHttpFilter Class Members for a list of functions you can override.

    The notification filters you choose in the ISAPI Extension Wizard will appear with the default implementation in your project. Choose only the notifications you want your filter to handle. Adding unnecessary notifications will affect the efficiency of your filter.

    You can add or delete notification functions manually in the project source files later.

  8. Click Finish to create the ISAPI extension.

To add your filter processing

  1. Specify the notifications you want in GetFilterVersion.

    dwFlags will already contain the filters for events you specified in the Extension Wizard.

  2. To add a new notification, add the filter flag to dwFlags in CHttpFilter::GetFilterVersion.
    • Add the filter function declaration to the .h file.

    • Add the filter definition to the .cpp file.

    You can remove notification flags and functions as well.

  3. To Implement your filter functions, open the .cpp file and add custom handling for your chosen filter notifications by replacing the //TODOs in the wizard-generated code.

  4. To add your filter to the registry, specify the full path and the name of your DLL.

    HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/W3SVC/Parameters/FilterDLLs is the registry key where filters are specified. Multiple entries are separated by commas and are loaded in the order specified.

To debug your filter, if running Microsoft Internet Information Server

  • Run INETINFO.EXE with local or remote debugging as described in ISAPI: Debugging

To load your filter, or to install a new version, if running Microsoft Internet Information Server

  • Shut down the WWW service, copy the new version of your DLL over the old one, and restart the service.

See Also CHttpFilter, CHttpFilterContext, Internet: Where Is...


ISAPI Extensions: Servers

Home | Overview | How Do I

This article describes the MFC classes used in writing ISAPI server extensions. Topics include:

  • Classes Used in Writing an ISA

  • Server Entry-Point Functions

  • The EXTENSION_CONTROL_BLOCK Structure

For a detailed list of steps to create your ISAPI server extension, see Steps to Create a Typical ISAPI Extension.

For an introduction to HTTP servers, see the article Internet Server API (ISAPI) Extensions. For a comparison of ISAPI and CGI, see How Does ISAPI Compare with CGI?.

The MFC Internet sample program WWWQUOTE illustrates how to use CHttpServer, CHttpServerContext, and CHtmlStream.

Classes Used in Writing an ISA

To write an ISA in MFC, create a CHttpServer object. Each time the CHttpServer receives a client request, it creates a CHttpServerContext object. It passes a pointer to that object to the command handling function. The use of multiple CHttpServerContext objects permits the CHttpServer object to handle a single command from a single client to the server object. Because the server may be handling concurrent, multiple requests, more than one active CHttpServerContext object can be associated with a particular CHttpServer instance.

Server Entry-Point Functions

Use the MFC class CHttpServer to create and manage a server extension DLL. Your server extension DLL should expose two entry points as exported functions: CHttpServer::GetExtensionVersion and CHttpServer::HttpExtensionProc. An extension DLL generated by the ISAPI Extension Wizard will have a .def file that correctly exports these functions. The functions are implemented by MFC, which simply finds the single CHttpExtension instance in the DLL and calls its CHttpServer::GetExtensionVersion or CHttpServer::HttpExtensionProc implementation as appropriate.

CHttpServer::GetExtensionVersion

When the server application is invoked for the first time, the server calls CHttpServer::GetExtensionVersion to perform two tasks:

  • Exchange version information

    The default implementation of GetExtensionVersion checks the version number for which you are creating your server extension against the server’s version number.

  • Provide a short text description of the ISA

    Override GetExtensionVersion to set the text string with your own description.

CHttpServer::HttpExtensionProc

The second CHttpServer member function to consider as an entry point is CHttpServer::HttpExtensionProc, which is similar to the main function of an application. It uses callback functions to read client data and determine the action to be taken. Usually, you won’t take direct action with HttpExtensionProc because MFC automatically handles incoming client requests by sending them through a parse map. The parse map is used to identify which of your functions to call, and to extract the function parameters. For information on using the parse map macros, see the article ISAPI Extensions: Parse Maps.

When HttpExtensionProc finishes, it returns a value, which the server then formats and returns to the client. For a list of the values returned, see the description for HttpExtensionProc in the Class Library Reference.

The default implementation of HttpExtensionProc is recommended; however, you can override it to provide custom implementation. For example, you could override this function to allocate per-call data.

The EXTENSION_CONTROL_BLOCK Structure

The HTTP server and the ISA communicate data through the EXTENSION_CONTROL_BLOCK structure. The information passed through the structure includes, for example, the raw query string, path information, method name, and translated path. MFC copies the EXTENSION_CONTROL_BLOCK pointer it receives from the server and passes it along in the CHttpServerContext object passed to command handling functions. Reference information about the EXTENSION_CONTROL_BLOCK structure, including a list of possible field values, is in the Class Library Reference.

See Also ISAPI Extensions: MFC Classes, ISAPI Extensions: Filters, Steps to Create a Typical ISAPI Filter, Internet: Where Is...


Steps to Create a Typical ISAPI Extension

Home | Overview | How Do I

After you have decided what your ISAPI Extension Server will do, you can get started by using the ISAPI Extension Wizard. For more information about starting a new project using wizards, see Visual C++ Wizards that Help You Begin Your Program. After the project has been created, you add your custom functionality. The steps are described below.

To create a project using the ISAPI Extension Wizard

  1. In the development environment, choose New from the File menu and click the Projects tab.

  2. On the Projects tab, click the ISAPI Extension Wizard and name your project.

  3. In Step 1 of the Extension Wizard, check the option to Generate a Server Extension object.

  4. Name your CHttpServer-derived extension class, and choose Finish to create the project.

To add your functions

  1. For each command, write a function.

    MFC passes a pointer to a CHttpServerContext object when calling your function. Much of the information you want to work with is in the object’s EXTENSION_CONTROL_BLOCK structure data member. You can also use member function callbacks to obtain additional header information, such as the user’s IP address.

  2. For each function, write a parse map entry for the required and optional parameters.

  3. Override CHttpExtensionProc, if you want to do custom processing.

To install your DLL

  • Copy your DLL into a directory for which users have execute privileges.

    For Microsoft Internet Information Server, you set execute permissions in Internet Service Manager.

Clients can now type the URL in the browser to invoke your DLL on the server.

See Also Internet: Where Is...


ISAPI Extensions: Parse Maps

Home | Overview | How Do I

A parse map consists of code you write so that a CHttpServer-derived object maps client requests to its member functions. MFC provides parse map macros to help you do this. This article demonstrates the use of the macros through a continuing example of a single command: RegisterUser. It provides examples of using the parse map, including working with optional and required parameters. Topics included in this article are:

  • The Parse Map Macros

  • Designing Fill-out Forms for Use with ISAPI Parse Map Macros

  • Processing HTML Forms Using Internet Server Extension DLLs and Command Handlers

  • Declaring a Command in a Parse Map

  • Passing a String from the URL

  • Naming Parameters with ON_PARSE_COMMAND_PARAMS

  • Managing Required and Optional Parameters

For more information on Internet server extension DLLs, which are also called Internet server applications (ISAs), see the article Internet Server API (ISAPI) Extensions. For more on the Internet Server API (ISAPI) classes wrapped by MFC, including CHttpServer, see the article ISAPI Extensions: MFC Classes.

The MFC Internet sample program WWWQUOTE contains a parse map in its file WWWQUOTE.CPP.

See Also CHttpServer, CHttpServerContext, CHtmlStream, Internet: Where Is...


The Parse Map Macros

Home | Overview | How Do I

The parse map process includes five macros:

  • BEGIN_PARSE_MAP Starts the definition of a parse map. It takes the member function’s class and its base class as parameters.

  • ON_PARSE_COMMAND Identifies a command. It takes the command, the member function’s class, and a list of parameter types as parameters.

  • ON_PARSE_COMMAND_PARAMS Defines the command’s parameter list. It must follow immediately after ON_PARSE_COMMAND. It takes as its parameters the arguments accepted from the client.

  • DEFAULT_PARSE_COMMAND Identifies the command used when no command is explicitly specified.

  • END_PARSE_MAP Ends the definition of a parse map.

What do you want to know more about?

  • Designing Fill-out Forms for Use with ISAPI Parse Map Macros

  • Processing HTML Forms Using Internet Server Extension DLLs and Command Handlers

  • Declaring a Command in a Parse Map

  • Passing a String from the URL

  • Naming Parameters with ON_PARSE_COMMAND_PARAMS

  • Managing Required and Optional Parameters


Designing Fill-out Forms for Use with ISAPI Parse Map Macros

Home | Overview | How Do I

When a CHttpServer object receives a client request, it uses a set of macros called a parse map that map the request to the appropriate CHttpServer member functions. The client request can either be a server GET method or a server POST method. Other methods, like HEAD, are not supported. You can add your own support by overriding CHttpServer::HttpExtensionProc.

Authors of ISAPI forms are advised to use only the POST method because of browser inconsistencies, and because GET methods are limited to a 1024-byte buffer for their parameters. When writing forms for ISAPI, either use only the POST method, or design the ISA so that only the default function handles the form.

For example, some browsers sending a form via GET with an action of:

TestLet.DLL?Command

will truncate Command and send

TestLet.DLL?name=value

instead of the correct command,

TestLet.DLL?Command?name=value

By truncating Command, the browser removes the association to the ISA function needed to map the request. Unless the function Command is the default function, the form will not be handled correctly.

What do you want to know more about?

  • Processing HTML Forms Using Internet Server Extension DLLs and Command Handlers

  • Declaring a Command in a Parse Map

  • Passing a String from the URL

  • Naming Parameters with ON_PARSE_COMMAND_PARAMS

  • Managing Required and Optional Parameters


Processing HTML Forms Using Internet Server Extension DLLs and Command Handlers

Home | Overview | How Do I

This topic describes how to use the MfcISAPICommand parameter in HTML forms.

Command Handlers

MFC's ISAPI classes for creating Internet server extension DLLs make use of "command handlers"?function names that are included in Uniform Resource Locators (URLs) and that allow a particular member function of a CHttpServer object to handle a request. Command handlers are defined with PARSE_MAP macros and are especially useful for processing HTML forms. For more information on defining command handlers, see the reference topic Internet Server API (ISAPI) Parse Maps.

Web Browser Inconsistencies

When creating your server extension DLLs and the Web pages that contain links or forms that call your extensions, you must keep in mind that although you control what happens on the server side, you do not have control over your users' Web browsers. For example, consider the following HTML form:

<FORM ACTION="http://www.moosegrrrl.com/scripts/MyExtension.dll?MyFunction" METHOD=GET>
Enter your full name: <INPUT NAME="name" VALUE="Anonymous">
<INPUT TYPE=SUBMIT VALUE="Register">
</FORM>

This form generates a request whose syntax depends on the individual browser. Microsoft Internet Explorer 3.x will send a command line such as:

http://www.moosegrrrl.com/scripts/MyExtension.dll?MyFunction?name=Anonymous

while Netscape Navigator 3.x will send:

http://www.moosegrrrl.com/scripts/MyExtension.dll?name=Anonymous

Microsoft Internet Explorer 3.x will append a question mark to the form's action if the form is being sent to the server by way of the GET method. It will not append a question mark to the action if the form's method is POST; however, there must be a question mark after the name of the extension DLL to indicate that the DLL is a script to be run, not an item to be downloaded. Netscape Navigator 3.x will, regardless of the method used to send a form or the syntax of the ACTION, always send a command line that contains one and only one question mark at the end of the action. Other versions of these browsers and browsers written by different companies may behave differently.

Using the New MfcISAPICommand Parameter

To provide you with a simple way to get around the issue of browser inconsistencies and still retain the ability to make use of command handlers, MFC version 4.2 has implemented the MfcISAPICommand parameter. If "MfcISAPICommand" is the first available parameter, its value will be the command handler used by the CHttpServer object to process the request. If the first available parameter is not "MfcISAPICommand", then the CHttpServer object will look to the first item on the command line following the name of the extension to determine which function to call, as it does in MFC 4.1 parameter processing.

Note Unless the "MfcISAPICommand" parameter is at the very beginning of the form data, it is processed as an ordinary parameter.

The following HTML form shows the suggested usage of the "MfcISAPICommand" parameter, which enables your Internet server extension to correctly handle requests generated by either Microsoft or Netscape browsers:

<FORM ACTION=" http://www.moosegrrrl.com/scripts/MyExtension.dll" METHOD=GET>
<INPUT TYPE=HIDDEN NAME="MfcISAPICommand" VALUE="MyFunction">
Enter your full name: <INPUT NAME="name" VALUE="Anonymous">
<INPUT TYPE=SUBMIT VALUE="Register">
</FORM>

What do you want to know more about?

  • Declaring a Command in a Parse Map

  • Passing a String from the URL

  • Naming Parameters with ON_PARSE_COMMAND_PARAMS

  • Managing Required and Optional Parameters


Declaring a Command in a Parse Map

Home | Overview | How Do I

The rest of this article is a continuing example of a parse map. The code examples demonstrate the parsing of a URL string, specifying default and required parameters, and using optional parameters. The example uses these elements:

Element | Name
Server | MOOSE
Server DLL | SURVEY.DLL
CHttpServer object | CServerDerived
Command | RegisterUser
User name | Richard M. Jones

The following parse map declares a single command, RegisterUser. This command accepts only one parameter: a pointer to a string:

BEGIN_PARSE_MAP( CServerDerived, CHttpServer )
ON_PARSE_COMMAND( RegisterUser, CServerDerived, ITS_PSTR )
END_PARSE_MAP( CServerDerived )

The corresponding command handler, RegisterUser, is a member of the CServerDerived class, and must be declared as follows:

CServerDerived::RegisterUser( CHttpServerContext* pCtxt, LPCTSTR pstrParameter )
{
   // do work here!
}

The first parameter of the handling member function must be a pointer to a CHttpServerContext object.

What do you want to know more about?

  • Passing a String from the URL

  • Naming Parameters with ON_PARSE_COMMAND_PARAMS

  • Managing Required and Optional Parameters


Passing a String from the URL

Home | Overview | How Do I

The next step in the example demonstrates invoking the command RegisterUser on the server MOOSE. The command RegisterUser is the name of a member function in the server DLL SURVEY.DLL. The client invokes RegisterUser from the following URL:

http://moose/survey/survey.dll?RegisterUser?Richard

This URL causes the member function RegisterUser to be called with pstrParameter pointing at the string “Richard”.

If Richard wanted to register his middle initial and last name too, the URL would look like this:

http://moose/survey/survey.dll?RegisterUser?Richard+M%2E+Jones

The string contains multiple words and punctuation, so the server expands the normal plus sign and percent sign URL character escapes before passing the string to the parse map. The character escapes are automatically filled into the URL by the browser and are not specific to ISAPI. For more information about the URL character escapes, see the Web site:

http://www.internic.net/rfc/rfc1738.txt

What do you want to know more about?

  • Naming Parameters with ON_PARSE_COMMAND_PARAMS

  • Managing Required and Optional Parameters


Naming Parameters with ON_PARSE_COMMAND_PARAMS

Home | Overview | How Do I

This part of the example shows how to use the ON_PARSE_COMMAND_PARAMS macro to name parameters. Named parameters can appear in any order, as long as they precede all optional ones. They are useful in writing a function with a variable number of parameters for responding to a submit button on an HTML form. For example, you can create an HTML form to collect name, address, or additional information. When the user clicks the submit button on the form, a URL containing the information the user entered is passed to the server. Your parse maps can specify default values for optional fields. For information about HTML tags that specify how a form’s content is sent to the server, see Internet First Steps: HTML.

The RegisterUser function takes three parameters: First, Middle, and Last:

BEGIN_PARSE_MAP( CServerDerived, CHttpServer )
ON_PARSE_COMMAND( RegisterUser, CServerDerived, ITS_PSTR ITS_PSTR ITS_PSTR )
ON_PARSE_COMMAND_PARAMS("First Middle Last")
END_PARSE_MAP( CServerDerived )

The corresponding command handler is written like this:

CServerDerived::RegisterUser( CHttpServerContext* pctxt, LPCTSTR pstrFirst, LPCTSTR pstrMiddle, LPCTSTR pstrLast )
{
   // do processing here!
}

For example, if the client uses a fill-in form with METHOD=GET, ACTION="http://mooseboy/survey/survey.dll?RegisterUser" and three text boxes named "First", "Middle", and "Last" to invoke RegisterUser, and the user enters the values "Richard", "M.", and "Jones", the URL will be formatted as follows:

http://mooseboy/survey/survey.dll?RegisterUser?First=Richard&Middle=M%2E&Last=Jones

The parse map looks at each name=value pair and assigns the value accordingly — all three parameters to RegisterUser will correctly resolve to "Richard", "M.", and "Jones", respectively.

What do you want to know more about?

  • Managing Required and Optional Parameters


Managing Required and Optional Parameters

Home | Overview | How Do I

This part of the example examines the technique of setting the parse map’s parameters as optional and how to handle data provided to an optional parameter. It also discusses the pitfalls of setting all parameters as required or all parameters as optional. Finally, it describes possible errors from failing to match the parameters with specified defaults.

In the example, the server MOOSE contains the DLL SURVEY.DLL, which contains the CHttpServer object CServerDerived. The client could use the following URL to invoke the RegisterUser command:

http://moose/survey/survey.dll?RegisterUser?Richard&M%2E&Jones

This command calls the member function RegisterUser with the parameters “Richard”, “M.”, and “Jones” for the pstrFirst, pstrMiddle, and pstrLast parameters, respectively.

Suppose the client used the following URL to call the RegisterUser function:

http://moose/survey/survey.dll?RegisterUser?Richard&Jones

Such a call would get an error from the server because in this example all three parameters — pstrFirst, pstrMiddle, and pstrLast — are required. You can make parameters optional by specifying defaults for them in the ON_PARSE_COMMAND_PARAMS macro. This map makes all of the parameters optional:

BEGIN_PARSE_MAP(CServerDerived, CHttpServer)
ON_PARSE_COMMAND(RegisterUser, CServerDerived, ITS_PSTR ITS_PSTR ITS_PSTR)
ON_PARSE_COMMAND_PARAMS("First=~ Middle=~ Last=~")
END_PARSE_MAP(CServerDerived)

The default parameters specified above are tildes, an easily identifiable character you can test for in your handling function.

If the client invokes RegisterUser by using the following URL:

http://moose/survey/survey.dll?RegisterUser?Richard

when you have the above map installed, the second and third parameters are resolved as tildes.

If the client invokes RegisterUser by using the following URL:

http://moose/survey/survey.dll?RegisterUser?Richard&M%2E&Jones

when you have the above map installed, all three parameters to the RegisterUser function will resolve correctly.

You can make some parameters optional and some parameters required, but the required parameters must always appear first ? before any optional parameters. For example, you can modify the map to indicate that only the parameter for the middle name is optional:

BEGIN_PARSE_MAP(CServerDerived, CHttpServer)
ON_PARSE_COMMAND(RegisterUser, CServerDerived, ITS_PSTR ITS_PSTR ITS_PSTR)
ON_PARSE_COMMAND_PARAMS("Last First Middle=~")
END_PARSE_MAP(CServerDerived)

Take care that the parameter types you specify match the parameter defaults you specify. You can accept both a string and an integer, for example,

BEGIN_PARSE_MAP(CServerDerived, CHttpServer)
ON_PARSE_COMMAND(Enlist, CServerDerived, ITS_PSTR ITS_I4)
ON_PARSE_COMMAND_PARAMS("Title=Developer Level=14")
END_PARSE_MAP(CServerDerived)

and produce the expected results. But if you were to reverse the two parameters, like this:

BEGIN_PARSE_MAP(CServerDerived, CHttpServer)
ON_PARSE_COMMAND(Enlist, CServerDerived, ITS_PSTR ITS_I4)
ON_PARSE_COMMAND_PARAMS("Level=14 Title=Developer")
END_PARSE_MAP(CServerDerived)

the default parameter for what you expected to be the level would be 0 and the title would be the string “14”.

To add a space to a default string, enclose the string in single quotation marks. You don’t need to escape special characters.

ON_PARSE_COMMAND_PARAMS("Title='Technical Writer' Level=14")

When passing an unknown number of parameters to the ISAPI extension, use the symbol ITS_RAW. For example, if your web page has a selection list from which one or more items can be selected, the following ON_PARSE_COMMAND specification is not appropriate, because its parameter list specifies that it receive exactly two pointers to strings:

ON_PARSE_COMMAND(Enlist, CServerDerived, ITS_PSTR ITS_PSTR)

If the ISAPI extension were to receive more or fewer than the specified number of parameters, an error will occur on the server. When the number of parameters to be passed is uncertain, you should call ON_PARSE_COMMAND with ITS_RAW. Note that you do not call ON_PARSE_COMMAND_PARAMS when parsing raw data. However, you must call DEFAULT_PARSE_COMMAND to specify the function that will pass the raw data:

BEGIN_PARSE_MAP(CDerivedExtension, CHttpServer)
DEFAULT_PARSE_COMMAND(Myfunc, CDerivedExtension)
ON_PARSE_COMMAND(Myfunc, CDerivedExtension, ITS_RAW)
END_PARSE_MAP(CDerivedExtension)

Use the following function prototype to send the data:

void CDerivedClass::Myfunc(CHttpServerContext* pCtxt, void* pVoid, DWORD dwBytes);

The pVoid pointer points to the data sent to your extension. The dwBytes parameter has a count of bytes at pVoid. If dwBytes is zero, it might indicate that pVoid points to nothing.

If the client invokes RegisterUser by using the following URL:

http://mooseboy/derived.dll?Myfunc&selection=10&selection=35&confirm=y

Myfunc would be called with pVoid pointing to the string "Myfunc&selection=10&selection=35&confirm=y" and dwBytes containing 42. Note that dwBytes does not count the trailing nul byte in the data referenced by pVoid, because pVoid points to exactly what the client sent to the extension. The client might or might not have sent a trailing nul byte, or it might have sent more than one nul byte in the data.

See Also CHttpServer, CHttpServerContext, CHtmlStream, ON_PARSE_COMMAND, DEFAULT_PARSE_COMMAND, Internet: Where Is...


ISAPI Programming Tips

Home | Overview | How Do I

It is important to remember that your ISAPI application is running in the context of a service on NT. This means your code must be thread safe, it must be reentrant, and it has no user interface on the server.

  • Watch your resource usage. Release acquired resources. For example, you might not be able to keep an ODBC connection for the life of the server.

  • Be thread safe. Use synchronization objects to protect data. Don’t use global variables.

  • Write your filters to use the appropriate priority notification, at the lowest priority possible. A filter to authorize users may need to run at high priority. In this case, if a user fails authorization, the other lower-priority filter notifications will never be called.

  • Be efficient in your filter processing. Filter functions can be called for all server requests, and an inefficient filter could slow down processing noticeably. If you are not using all the filter notifications you originally specified, alter dwFlags in GetFilterVersion to delete unneeded notifications.

  • Do not display dialog boxes on the server, which may be running unattended with no one to click OK. Instead, log error information to a log file or a database.

Server Extension (ISA) Memory Management

If you want to allocate data on a per-call basis, you must use the data carefully within a synchronization object. The example below demonstrates overriding the HttpExtensionProc member function and using a critical section to associate per-call data with the ConnID. The base class is then called to process the request. Any member functions that use the data must protect it with a synchronization object. Upon return from HttpExtensionProc processing, the data for that ConnID is freed.

// in your .H file, declare variables and override HttpExtensionProc
class CISAPIWizExtension : public CHttpServer
{
    // per-call data
    CString* pData;
    CCriticalSection m_critSect;
    CMap < HCONN, HCONN&, CString*, CString* > m_map;

    // allocate per-call data
    DWORD HttpExtensionProc(EXTENSION_CONTROL_BLOCK* pECB);
};

// in your .CPP file, override HttpExtensionProc,
// to set per-call data for this connection
DWORD CISAPIWizExtension::HttpExtensionProc(EXTENSION_CONTROL_BLOCK* pECB)
{
    DWORD dwResult;
    // allocate per-call data
    // using the data type of your choice
    pData = new CString("whatever data you want");
    m_critSect.Lock();
    m_map.SetAt(pECB->ConnID, pData);
    m_critSect.Unlock();

    // call base class to do the work
    // remember, any member functions
    // that use the per-call data
    // must also access it within critical sections
    dwResult = CHttpServer::HttpExtensionProc(pECB);

    // delete per-call data
    m_critSect.Lock();
    m_map.Lookup(pECB->ConnID, pData);
    m_map.RemoveKey(pECB->ConnID);
    delete pData;
    m_critSect.Unlock();
    return dwResult;
}

Filter Memory Management

Most filters will register for the end of net session event. You can use this event to recycle any buffers used by that client request. For performance reasons, most filters will probably keep a pool of filter buffers and only allocate or free memory when the pool becomes empty or so large it no longer saves on the overhead of memory management. To allocate memory that is automatically freed when the communication with the client is terminated, use CHttpFilterContext::AllocMem. Using AllocMem presents a tradeoff: It is a valuable memory management tool, but it can affect performance, as noted earlier.

See Also Internet First Steps: Application Design Choices, ISAPI: Debugging, Internet: Where Is..., ISAPI: Debugging


ISAPI: Debugging

Home | Overview | How Do I

Preparing to debug your program requires careful attention to the setup steps. A detailed list of steps to set up your server for debugging is in technical note TN063: Debugging Internet Extension DLLs.

Getting Ready to Debug Your Application

The general steps to prepare for debugging include:

  • Creating a project file that sets up a workspace for the server application, with options to run the service interactively, and specifying a list of the DLLs you will be debugging.

  • Setting up permissions in the Windows NT User Manager. You must log off and log back on for the permissions to take effect.

  • Stopping and restarting the service.

If you follow the steps in Technical Note 63 carefully, you will be able to set breakpoints for any of your filters and extensions from one project file based on the Internet server program you are running. If your debugging session doesn’t stop on the breakpoints you’ve set, go through the steps again. In particular, be sure you have installed the right files on the right computers and have set the appropriate permissions.

After you have successfully completed the setup described in Technical Note 63, you can debug locally on your server. It is often useful to be able to debug remotely, from another machine, because you may not always have access to the server, or it may not have a development environment installed. You can follow the steps described in Debugging Remote Applications to set up a Windows NT workstation computer to remotely debug an ISAPI DLL without logging on to the server directly.

Additional Steps For Remote Debugging

Additional steps to prepare for remote debugging include:

  • Set up both computers: the server (target) and the computer on which you will be running the debugging session and setting breakpoints (host).

  • Install remote debug monitor files, run MSVCMON.EXE, and follow the additional steps as described in the article Debugging Remote Applications. Install project files on both computers.

  • In the development environment, specify additional debug settings, including the remote executable file name. From the Build menu, specify the server computer name as the Debugger Remote Connection.

See Also Internet: Where Is...


ISAPI and Databases

Home | Overview | How Do I

You must ensure that the database driver is thread safe: Not all are!

Microsoft SQL Server 6.x driver is thread safe. Check the documentation for other drivers.

Note that you can also use DB Connector, which comes with the Internet Information Server, to create front ends with simple forms and queries for your database applications. See the documentation for Internet Information Server for more information.

Create your database connection in an appropriate way. Remember that your DLL may remain in memory until the server shuts down, and you may need to reestablish your database connection at various times during the lifetime of the service.

When Should I Use ISAPI With a Database?

If you already have client/server solutions using SQL Server, you may be able to use them. If you are using HTML on the client side, you can continue to do so. You can also use DB Connector, which is a part of the Microsoft Internet Information Server that makes it easy for you to build simple front ends to run on your server. ISAPI provides access to the full power of SQL and is needed for more complex database queries.

Browsers handle form processing differently. For more information, see Processing HTML Forms Using Internet Server Extension DLLs and Command Handlers.

See Also TN067: Database Access from an ISAPI Server Extension, Internet: Where Is...


ISAPI: Getting More Information

Home | Overview | How Do I

Additional information can be found in a variety of sources. Please note that Web links may change without notice.

For information about Internet Information Server, see the Microsoft Internet Information Server web site:

http://www.microsoft.com/iis

See Also Internet: Where Is...


MAPI Topics

Home | Overview | How Do I | Sample

This article describes MAPI, the Microsoft Messaging Application Programming Interface for client message application developers. MFC supplies support for a subset of MAPI in class CDocument but does not encapsulate the entire API. For more information, see MAPI Support in MFC.

MAPI is a set of functions that mail-enabled and mail-aware applications use to create, manipulate, transfer, and store mail messages. It gives application developers the tools to define the purpose and content of mail messages, and gives them flexibility in their management of stored mail messages. MAPI also provides a common interface that application developers can use to create mail-enabled and mail-aware applications independent of the underlying messaging system.

Messaging clients provide a human interface for interaction with the Microsoft Windows Messaging System (WMS). This interaction typically includes requesting services from MAPI-compliant providers such as message stores and address books.

For more information about MAPI, see the articles under Guide in Win32 Messaging (MAPI) of the Win32 SDK.

What do you want to know more about?

  • Enabling my program for sending mail

  • MAPI support in MFC


MAPI Support in MFC

Home | Overview | How Do I | Sample

MFC supplies support for a subset of the Microsoft Messaging Application Program Interface (MAPI) in class CDocument. Specifically, CDocument has member functions that determine whether mail support is present on the end-user’s machine and, if so, enable a Send Mail command whose standard command ID is ID_FILE_SEND_MAIL. The MFC handler function for this command allows the user to send a document via electronic mail.

Tip Although MFC does not encapsulate the entire MAPI function set, you can still call MAPI functions directly, just as you can call Win32 API functions directly from MFC programs.

Providing the Send Mail command in your application is very easy. MFC provides the implementation to package a document (that is, a CDocument-derived object) as an attachment and send it as mail. This attachment is equivalent to a File Save command that saves (serializes) the document’s contents to the mail message. This implementation calls upon the mail client on the user’s machine to give the user the opportunity to address the mail and to add subject and message text to the mail message. Users see their familiar mail application’s user interface. This functionality is supplied by two CDocument member functions: OnFileSendMail and OnUpdateFileSendMail.

MAPI needs to read the file to send the attachment. If the application keeps its data file open during an OnFileSendMail function call, the file needs to be opened with a share mode that allows multiple processes to access the file.

Note An overriding version of OnFileSendMail for class COleDocument correctly handles compound documents.

To implement a Send Mail command with MFC

  1. Use the Visual C++ menu editor to add a menu item whose command ID is ID_FILE_SEND_MAIL.

    This command ID is provided by the framework in AFXRES.H. The command can be added to any menu, but it is usually added to the File menu.

  2. Manually add the following to your document’s message map:
    ON_COMMAND(ID_FILE_SEND_MAIL, OnFileSendMail)
ON_UPDATE_COMMAND_UI(ID_FILE_SEND_MAIL, OnUpdateFileSendMail)

    Place the new lines outside of the special “//{{AFX” comments.

    Note This message map works for a document derived from either CDocument or ColeDocument — it picks up the correct base class in either case, even though the message map is in your derived document class.

  3. Build your application.

If mail support is available, MFC enables your menu item with OnUpdateFileSendMail and subsequently processes the command with OnFileSendMail. If mail support is not available, MFC automatically removes your menu item so the user will not see it.

Tip Rather than manually adding message map entries as described above, you can use ClassWizard to add them, although the method is indirect. To use ClassWizard, add an OnFileSendMail command handler and an OnUpdateFileSendMail command update handler as you normally would. This gives you two empty handlers that effectively override the OnFileSendMail and OnUpdateFileSendMail handlers in CDocument, which contain the MAPI implementations. To use those implementations, call the base-class versions of OnFileSendMail and OnUpdateFileSendMail in your new handlers. While this approach works, manually adding the message map entries, as described in the procedure above, is quicker and more direct.

Note also that the MFC AppWizard lets you select an option that adds MAPI support directly to your new MFC application. If you use that option, you can skip steps 1 and 2 above.

For related information, see MAPI Topics.

What do you want to do?

  • Learn more about the CDocument member functions that enable MAPI:
    • CDocument::OnFileSendMail

    • CDocument::OnUpdateFileSendMail

    • COleDocument::OnFileSendMail


Memory Management Topics (MFC)

Home | Overview | How Do I

This group of articles describes how to take advantage of the general-purpose services of the Microsoft Foundation Class Library (MFC) related to memory management. Memory allocation can be divided into two main categories: frame allocations and heap allocations.

One main difference between the two allocation techniques is that with frame allocation you typically work with the actual memory block itself, while with heap allocation you are always given a pointer to the memory block. Another major difference between the two schemes is that frame objects are automatically deleted, while heap objects must be explicitly deleted by the programmer.

What do you want to know more about?

  • Frame allocation

  • Heap allocation

  • Allocating memory for an array

  • Allocating memory for a data structure

  • Allocating memory for an object

  • Resizable memory blocks


Memory Management: Frame Allocation

Home | Overview | How Do I

Allocation on the frame takes its name from the “stack frame” that is set up whenever a function is called. The stack frame is an area of memory that temporarily holds the arguments to the function as well as any variables that are defined local to the function. Frame variables are often called “automatic” variables because the compiler automatically allocates the space for them.

There are two key characteristics of frame allocations. First, when you define a local variable, enough space is allocated on the stack frame to hold the entire variable, even if it is a large array or data structure. Second, frame variables are automatically deleted when they go out of scope:

void MyFunction( )
{
    // Local object created on the stack
    CString strName;
    ...
    // Object goes out of scope and is deleted as function ends
}

For local function variables, this scope transition happens when the function exits, but the scope of a frame variable can be smaller than a function if nested braces are used. This automatic deletion of frame variables is very important. In the case of simple primitive types (such as int or byte), arrays, or data structures, the automatic deletion simply reclaims the memory used by the variable. Since the variable has gone out of scope, it cannot be accessed anyway. In the case of C++ objects, however, the process of automatic deletion is a bit more complicated.

When an object is defined as a frame variable, its constructor is automatically invoked at the point where the definition is encountered. When the object goes out of scope, its destructor is automatically invoked before the memory for the object is reclaimed. This automatic construction and destruction can be very handy, but you must be aware of the automatic calls, especially to the destructor.

The key advantage of allocating objects on the frame is that they are automatically deleted. When you allocate your objects on the frame, you don’t have to worry about forgotten objects causing memory leaks. (For details on memory leaks, see the article Diagnostics: Detecting Memory Leaks.) A disadvantage of frame allocation is that frame variables cannot be used outside their scope. Another factor in choosing frame allocation versus heap allocation is that for large structures and objects, it is often better to use the heap instead of the stack for storage since stack space is often limited.


Memory Management: Heap Allocation

Home | Overview | How Do I

The heap is reserved for the memory allocation needs of the program. It is an area apart from the program code and the stack. Typical C programs use the functions malloc and free to allocate and deallocate heap memory. The Debug version of MFC provides modified versions of the C++ built-in operators new and delete to allocate and deallocate objects in heap memory.

When you use new and delete instead of malloc and free, you are able to take advantage of the class library’s memory-management debugging enhancements, which can be useful in detecting memory leaks. When you build your program with the Release version of MFC, the standard versions of the new and delete operators provide an efficient way to allocate and deallocate memory (the Release version of MFC does not provide modified versions of these operators).

Note that the total size of objects allocated on the heap is limited only by your system’s available virtual memory.


Memory Management: Examples

Home | Overview | How Do I

This article describes how MFC performs frame allocations and heap allocations for each of the three typical kinds of memory allocations:

  • An array of bytes

  • A data structure

  • An object

Allocation of an Array of Bytes

To allocate an array of bytes on the frame

  • Define the array as shown by the following code. The array is automatically deleted and its memory reclaimed when the array variable exits its scope.
    {
    const int BUFF_SIZE = 128;

    // Allocate on the frame
    char myCharArray[BUFF_SIZE];
    int myIntArray[BUFF_SIZE];
    // Reclaimed when exiting scope
}

To allocate an array of bytes (or any primitive data type) on the heap

  • Use the new operator with the array syntax shown in this example:
    const int BUFF_SIZE = 128;

// Allocate on the heap
char* myCharArray = new char[BUFF_SIZE];
int* myIntArray = new int[BUFF_SIZE];

To deallocate the arrays from the heap

  • Use the delete operator as follows:
    delete [] myCharArray;
delete [] myIntArray;

Allocation of a Data Structure

To allocate a data structure on the frame

  • Define the structure variable as follows:
    struct MyStructType { int topScore;};
void SomeFunc(void)
{
    // Frame allocation
    MyStructType myStruct;

    // Use the struct
    myStruct.topScore = 297;

    // Reclaimed when exiting scope
}

    The memory occupied by the structure is reclaimed when it exits its scope.

To allocate data structures on the heap

  • Use new to allocate data structures on the heap and delete to deallocate them, as shown by the following examples:
    // Heap allocation
MyStructType* myStruct = new MyStructType;

// Use the struct through the pointer ...
myStruct->topScore = 297;

delete myStruct;

Allocation of an Object

To allocate an object on the frame

  • Declare the object as follows:
    {
CPerson myPerson;     // Automatic constructor call here

myPerson.SomeMemberFunction();     // Use the object

}

    The destructor for the object is automatically invoked when the object exits its scope.

To allocate an object on the heap

  • Use the new operator, which returns a pointer to the object, to allocate objects on the heap. Use the delete operator to delete them.

    The following heap and frame examples assume that the CPerson constructor takes no arguments.

    // Automatic constructor call here
CPerson* myPerson = new CPerson;

myPerson->SomeMemberFunction();            // Use the object

delete myPerson;                    // Destructor invoked during delete

    If the argument for the CPerson constructor is a pointer to char, the statement for frame allocation is:

    CPerson myPerson( "Joe Smith" );

    The statement for heap allocation is:

    CPerson* MyPerson = new CPerson( "Joe Smith" );


Memory Management: Resizable Memory Blocks

Home | Overview | How Do I

The new and delete operators, described in the article Memory Management: Examples, are good for allocating and deallocating fixed-size memory blocks and objects. Occasionally, your application may need resizable memory blocks. You must use the standard C run-time library functions malloc, realloc, and free to manage resizable memory blocks on the heap.

Important Mixing the new and delete operators with the resizable memory-allocation functions on the same memory block will result in corrupted memory in the Debug version of MFC. You should not use realloc on a memory block allocated with new. Likewise, you should not allocate a memory block with the new operator and delete it with free, or use the delete operator on a block of memory allocated with malloc.


Message Handling and Mapping Topics

Home | Overview | How Do I | Tutorial

This article family describes how messages and commands are processed by the MFC framework and how you connect them to their handler functions using ClassWizard.

What do you want to know more about?

  • Messages and commands

  • Message categories

  • How the framework calls a message handler

  • Message maps

  • Handling ranges of messages

  • Handling reflected messages in a control

  • Managing messages and commands with ClassWizard

  • Dynamic update of user-interface objects

  • Dynamic display of command information in the status bar


Messages and Commands in the Framework

Home | Overview | How Do I | Tutorial

Applications written for Microsoft Windows are “message driven.” In response to events such as mouse clicks, keystrokes, window movements, and so on, Windows sends messages to the proper window. Framework applications process Windows messages like any other application for Windows. But the framework also provides some enhancements that make processing messages easier, more maintainable, and better encapsulated.

The following topics introduce the key terms used in the rest of the article family to discuss messages and commands:

  • Messages

  • Message handlers

  • Message categories

  • Windows messages and control-notification messages

  • Command messages

  • Message maps

  • User-interface objects and command IDs

  • Command targets


Messages

Home | Overview | How Do I | Tutorial

The message loop in the Run member function of class CWinApp retrieves queued messages generated by various events. For example, when the user clicks the mouse, Windows sends several mouse-related messages, such as WM_LBUTTONDOWN when the left mouse button is pressed and WM_LBUTTONUP when the left mouse button is released. The framework’s implementation of the application message loop dispatches the message to the appropriate window.

The important categories of messages are described in Message Categories.


Message Handlers

Home | Overview | How Do I | Tutorial

In MFC, a dedicated handler function processes each separate message. Message-handler functions are member functions of a class. This documentation uses the terms message-handler member function, message-handler function, message handler, and handler interchangeably. Some kinds of message handlers are also called “command handlers.”

Writing message handlers accounts for a large proportion of your work in writing a framework application. This article family describes how the message-processing mechanism works.

What does the handler for a message do? It does whatever you want done in response to that message. ClassWizard will create the handlers for you and allow you to implement them. You can jump directly from ClassWizard to the handler function’s definition in your source files and fill in the handler’s code using the Visual C++ source code editor. Or you can create all of your handlers with ClassWizard, then move to the editor to fill in all functions at once. For details on using ClassWizard, see How to Manage Commands and Messages with ClassWizard.

You can use all of the facilities of Microsoft Visual C++ and MFC to write your handlers. For a list of all classes, see About the Microsoft Foundation Classes in the Class Library Reference.


Message Categories

Home | Overview | How Do I | Tutorial

What kinds of messages do you write handlers for? There are three main categories:

  1. Windows messages

    This includes primarily those messages beginning with the WM_ prefix, except for WM_COMMAND. Windows messages are handled by windows and views. These messages often have parameters that are used in determining how to handle the message.

  2. Control notifications

    This includes WM_COMMAND notification messages from controls and other child windows to their parent windows. For example, an edit control sends its parent a WM_COMMAND message containing the EN_CHANGE control-notification code when the user has taken an action that may have altered text in the edit control. The window’s handler for the message responds to the notification message in some appropriate way, such as retrieving the text in the control.

    The framework routes control-notification messages like other WM_ messages. One exception, however, is the BN_CLICKED control-notification message sent by buttons when the user clicks them. This message is treated specially as a command message and routed like other commands.

  3. Command messages

    This includes WM_COMMAND notification messages from user-interface objects: menus, toolbar buttons, and accelerator keys. The framework processes commands differently from other messages, and they can be handled by more kinds of objects, as explained in Command Targets.

Windows Messages and Control-Notification Messages

Messages in categories 1 and 2 — Windows messages and control notifications — are handled by windows: objects of classes derived from class CWnd. This includes CFrameWnd, CMDIFrameWnd, CMDIChildWnd, CView, CDialog, and your own classes derived from these base classes. Such objects encapsulate an HWND, a handle to a Windows window.

Command Messages

Messages in category 3 — commands — can be handled by a wider variety of objects: documents, document templates, and the application object itself in addition to windows and views. When a command directly affects some particular object, it makes sense to have that object handle the command. For example, the Open command on the File menu is logically associated with the application: the application opens a specified document upon receiving the command. So the handler for the Open command is a member function of the application class. For more about commands and how they are routed to objects, see How the Framework Calls a Handler.


Mapping Messages

Home | Overview | How Do I | Tutorial

Each framework class that can receive messages or commands has its own “message map.” The framework uses message maps to connect messages and commands to their handler functions. Any class derived from class CCmdTarget can have a message map. Other articles explain message maps in detail and describe how to use them.

In spite of the name “message map,” message maps handle both messages and commands — all three categories of messages listed in Message Categories.


User-Interface Objects and Command IDs

Home | Overview | How Do I | Tutorial

Menu items, toolbar buttons, and accelerator keys are “user-interface objects” capable of generating commands. Each such user-interface object has an ID. You associate a user-interface object with a command by assigning the same ID to the object and the command. As explained in Messages, commands are implemented as special messages. The figure “Commands in the Framework” below shows how the framework manages commands. When a user-interface object generates a command, such as ID_EDIT_CLEAR_ALL, one of the objects in your application handles the command — in the figure below, the document object’s OnEditClearAll function is called via the document’s message map.

Commands in the Framework

The figure “Command Updating in the Framework” below shows how MFC updates user-interface objects such as menu items and toolbar buttons. Before a menu drops down, or during the idle loop in the case of toolbar buttons, MFC routes an update command. In the figure below, the document object calls its update command handler, OnUpdateEditClearAll, to enable or disable the user-interface object.

Command Updating in the Framework


Command Targets

Home | Overview | How Do I | Tutorial

The figure Commands in the Framework shows the connection between a user-interface object, such as a menu item, and the handler function that the framework calls to carry out the resulting command when the object is clicked.

Windows sends messages that are not command messages directly to a window whose handler for the message is then called. However, the framework routes commands to a number of candidate objects — called “command targets” — one of which normally invokes a handler for the command. The handler functions work the same way for both commands and standard Windows messages, but the mechanisms by which they are called are different, as explained in How the Framework Calls a Handler.


How the Framework Calls a Handler

Home | Overview | How Do I | Tutorial

The following topics first examine how the framework routes commands, then examine how other messages and control notifications are sent to windows:

  • Message sending and receiving

  • How noncommand messages reach their handlers

  • Command routing

  • Command Routing Example

  • The OnCmdMsg Handler

  • Overriding the Standard Command Routing


Message Sending and Receiving

Home | Overview | How Do I | Tutorial

Consider the sending part of the process and how the framework responds.

Most messages result from user interaction with the program. Commands are generated by mouse clicks in menu items or toolbar buttons or by accelerator keystrokes. The user also generates Windows messages by, for example, moving or resizing a window. Other Windows messages are sent when events such as program startup or termination occur, as windows get or lose the focus, and so on. Control-notification messages are generated by mouse clicks or other user interactions with a control, such as a button or list-box control in a dialog box.

The Run member function of class CWinApp retrieves messages and dispatches them to the appropriate window. Most command messages are sent to the main frame window of the application. The WindowProc predefined by the class library gets the messages and routes them differently, depending on the category of message received.

Now consider the receiving part of the process.

The initial receiver of a message must be a window object. Windows messages are usually handled directly by that window object. Command messages, usually originating in the application’s main frame window, get routed to the command-target chain described in Command Routing.

Each object capable of receiving messages or commands has its own message map that pairs a message or command with the name of its handler.

When a command-target object receives a message or command, it searches its message map for a match. If it finds a handler for the message, it calls the handler. For more information about how message maps are searched, see How the Framework Searches Message Maps. Refer again to the figure Commands in the Framework.


How Noncommand Messages Reach Their Handlers

Home | Overview | How Do I | Tutorial

Unlike commands, standard Windows messages do not get routed through a chain of command targets but are usually handled by the window to which Windows sends the message. The window might be a main frame window, an MDI child window, a standard control, a dialog box, a view, or some other kind of child window.

At run time, each Windows window is attached to a window object (derived directly or indirectly from CWnd) that has its own associated message map and handler functions. The framework uses the message map — as for a command — to map incoming messages to handlers.


Command Routing

Home | Overview | How Do I | Tutorial

Your responsibility in working with commands is limited to making message-map connections between commands and their handler functions, a task for which you use ClassWizard. You must also write most command handlers.

Windows messages are usually sent to the main frame window, but command messages are then routed to other objects. The framework routes commands through a standard sequence of command-target objects, one of which is expected to have a handler for the command. Each command-target object checks its message map to see if it can handle the incoming message.

Different command-target classes check their own message maps at different times. Typically, a class routes the command to certain other objects to give them first chance at the command. If none of those objects handles the command, the original class checks its own message map. Then, if it can’t supply a handler itself, it may route the command to yet more command targets. The table Standard Command Route below shows how each of the classes structures this sequence. The general order in which a command target routes a command is:

  1. To its currently active child command-target object.

  2. To itself.

  3. To other command targets.

How expensive is this routing mechanism? Compared to what your handler does in response to a command, the cost of the routing is low. Bear in mind that the framework generates commands only when the user interacts with a user-interface object.

Standard Command Route

When an object of this type receives a command . . . It gives itself and other command-target objects a chance to handle the command in this order:
MDI frame window
(CMDIFrameWnd)
  1. Active CMDIChildWnd

  2. This frame window

  3. Application (CWinApp object)
Document frame window
(CFrameWnd, CMDIChildWnd)
  1. Active view

  2. This frame window

  3. Application (CWinApp object)
View
  1. This view

  2. Document attached to the view
Document
  1. This document

  2. Document template attached to the document
Dialog box
  1. This dialog box

  2. Window that owns the dialog box

  3. Application (CWinApp object)

Where numbered entries in the second column of the preceding table mention other objects, such as a document, see the corresponding item in the first column. For instance, when you read in the second column that the view forwards a command to its document, see the “Document” entry in the first column to follow the routing further.


Command Routing Example

Home | Overview | How Do I | Tutorial

To illustrate, consider a command message from a Clear All menu item in an MDI application’s Edit menu. Suppose the handler function for this command happens to be a member function of the application’s document class. Here’s how that command reaches its handler after the user chooses the menu item:

  1. The main frame window receives the command message first.

  2. The main MDI frame window gives the currently active MDI child window a chance to handle the command.

  3. The standard routing of an MDI child frame window gives its view a chance at the command before checking its own message map.

  4. The view checks its own message map first and, finding no handler, next routes the command to its associated document.

  5. The document checks its message map and finds a handler. This document member function is called and the routing stops.

If the document did not have a handler, it would next route the command to its document template. Then the command would return to the view and then the frame window. Finally, the frame window would check its message map. If that check failed as well, the command would be routed back to the main MDI frame window and then to the application object — the ultimate destination of unhandled commands.


The OnCmdMsg Handler

Home | Overview | How Do I | Tutorial

To accomplish the routing of commands, each command target calls the OnCmdMsg member function of the next command target in the sequence. Command targets use OnCmdMsg to determine whether they can handle a command and to route it to another command target if they cannot handle it.

Each command-target class may override the OnCmdMsg member function. The overrides let each class route commands to a particular next target. A frame window, for example, always routes commands to its current child window or view, as shown in the table Standard Command Route.

The default CCmdTarget implementation of OnCmdMsg uses the message map of the command-target class to search for a handler function for each command message it receives — in the same way that standard messages are searched. If it finds a match, it calls the handler. Message-map searching is explained in How the Framework Searches Message Maps.


Overriding the Standard Command Routing

Home | Overview | How Do I | Tutorial

In rare cases when you must implement some variation of the standard framework routing, you can override it. The idea is to change the routing in one or more classes by overriding OnCmdMsg in those classes. Do so:

  • In the class that breaks the order to pass to a nondefault object.

  • In the new nondefault object or in command targets it might in turn pass commands to.

If you insert some new object into the routing, its class must be a command-target class. In your overriding versions of OnCmdMsg, be sure to call the version that you’re overriding. See the OnCmdMsg member function of class CCmdTarget in the Class Library Reference and the versions in such classes as CView and CDocument in the supplied source code for examples.


How the Framework Searches Message Maps

Home | Overview | How Do I | Tutorial

The framework searches the message-map table for matches with incoming messages. Once you use ClassWizard to write a message-map entry for each message you want a class to handle and to write the corresponding handlers, the framework calls your handlers automatically. The following topics explain message-map searching:

  • Where to find message maps

  • Derived message maps

  • Mapping ranges of messages, command IDs, or control IDs to one handler


Where to Find Message Maps

Home | Overview | How Do I | Tutorial

When you create a new skeleton application with AppWizard, AppWizard writes a message map for each command-target class it creates for you. This includes your derived application, document, view, and frame-window classes. Some of these message maps already have AppWizard-supplied entries for certain messages and predefined commands, and some are just placeholders for handlers that you will add.

A class’s message map is located in the .CPP file for the class. Working with the basic message maps that AppWizard creates, you use ClassWizard to add entries for the messages and commands that each class will handle. A typical message map might look like the following after you add some entries:

BEGIN_MESSAGE_MAP(CMyView, CView)
   //{{AFX_MSG_MAP(CMyView)
   ON_WM_MOUSEACTIVATE()
   ON_COMMAND(ID_EDIT_CLEAR_ALL, OnEditClearAll)
   ON_UPDATE_COMMAND_UI(ID_EDIT_CLEAR_ALL, OnUpdateEditClearAll)
   ON_BN_CLICKED(ID_MY_BUTTON, OnMyButton)
   //}}AFX_MSG_MAP
END_MESSAGE_MAP()

The message map consists of a collection of macros. Two macros, BEGIN_MESSAGE_MAP and END_MESSAGE_MAP, bracket the message map. Other macros, such as ON_COMMAND, fill in the message map’s contents.

Note The message-map macros are not followed by semicolons.

The message map also includes comments of the form

//{{AFX_MSG_MAP(CMyView)
//}}AFX_MSG_MAP

that bracket many of the entries (but not necessarily all of them). ClassWizard uses these special comments when it writes entries for you. All ClassWizard entries go between the comment lines.

When you use ClassWizard to create a new class, it provides a message map for the class. Alternatively, you can create a message map manually using the source code editor.


Derived Message Maps

Home | Overview | How Do I | Tutorial

During message handling, checking a class’s own message map is not the end of the message-map story. What happens if class CMyView (derived from CView) has no matching entry for a message?

Keep in mind that CView, the base class of CMyView, is derived in turn from CWnd. Thus CMyView is a CView and is a CWnd. Each of those classes has its own message map. The figure “A View Hierarchy” below shows the hierarchical relationship of the classes, but keep in mind that a CMyView object is a single object that has the characteristics of all three classes.

A View Hierarchy

So if a message can’t be matched in class CMyView’s message map, the framework also searches the message map of its immediate base class. The BEGIN_MESSAGE_MAP macro at the start of the message map specifies two class names as its arguments:

BEGIN_MESSAGE_MAP(CMyView, CView)

The first argument names the class to which the message map belongs. The second argument provides a connection with the immediate base class — CView here — so the framework can search its message map, too.

The message handlers provided in a base class are thus inherited by the derived class. This is very similar to normal virtual member functions without needing to make all handler member functions virtual.

If no handler is found in any of the base-class message maps, default processing of the message is performed. If the message is a command, the framework routes it to the next command target. If it is a standard Windows message, the message is passed to the appropriate default window procedure.

To speed message-map matching, the framework caches recent matches on the likelihood that it will receive the same message again. One consequence of this is that the framework processes unhandled messages quite efficiently. Message maps are also more space-efficient than implementations that use virtual functions.


Declaring Message Handler Functions

Home | Overview | How Do I | Tutorial

Certain rules and conventions govern the names of your message-handler functions. These depend on the message category, as described in the following topics:

  • Handlers for standard Windows messages

  • Handlers for commands and control notifications

  • Handlers for ranges of messages

  • Handling reflected messages


Handlers for Standard Windows Messages

Home | Overview | How Do I | Tutorial

Default handlers for standard Windows messages (WM_) are predefined in class CWnd. The class library bases names for these handlers on the message name. For example, the handler for the WM_PAINT message is declared in CWnd as:

afx_msg void OnPaint();

The afx_msg keyword suggests the effect of the C++ virtual keyword by distinguishing the handlers from other CWnd member functions. Note, however, that these functions are not actually virtual; they are instead implemented through message maps. Message maps depend solely on standard preprocessor macros, not on any extensions to the C++ language. The afx_msg keyword resolves to white space after preprocessing.

To override a handler defined in a base class, simply use ClassWizard to define a function with the same prototype in your derived class and to make a message-map entry for the handler. Your handler “overrides” any handler of the same name in any of your class’s base classes.

In some cases, your handler should call the overridden handler in the base class so the base class(es) and Windows can operate on the message. Where you call the base-class handler in your override depends on the circumstances. Sometimes you must call the base-class handler first and sometimes last. Sometimes you call the base-class handler conditionally, if you choose not to handle the message yourself. Sometimes you should call the base-class handler, then conditionally execute your own handler code, depending on the value or state returned by the base-class handler.

Important It is not safe to modify the arguments passed into a handler if you intend to pass them to a base-class handler. For example, you might be tempted to modify the nChar argument of the OnChar handler (to convert to uppercase, for example). This behavior is fairly obscure, but if you need to accomplish this effect, use the CWnd member function SendMessage instead.

How do you determine the proper way to override a given message? ClassWizard helps with this decision. When ClassWizard writes the skeleton of the handler function for a given message — an OnCreate handler for WM_CREATE, for example — it sketches in the form of the recommended overridden member function. The following example recommends that the handler first call the base-class handler and proceed only on condition that it does not return –1.

int CMyView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;
    // TODO: Add your specialized creation code here
    return 0;
}

By convention, the names of these handlers begin with the prefix “On.” Some of these handlers take no arguments, while others take several. Some also have a return type other than void. The default handlers for all WM_ messages are documented in the Class Library Reference as member functions of class CWnd whose names begin with “On.” The member function declarations in CWnd are prefixed with afx_msg.


Handlers for Commands and Control Notifications

Home | Overview | How Do I | Tutorial

There are no default handlers for commands or control-notification messages. Therefore, you are bound only by convention in naming your handlers for these categories of messages. When you map the command or control notification to a handler, ClassWizard proposes a name based on the command ID or control-notification code. You can accept the proposed name, change it, or replace it.

Convention suggests that you name handlers in both categories for the user-interface object they represent. Thus a handler for the Cut command on the Edit menu might be named

afx_msg void OnEditCut();

Because the Cut command is so commonly implemented in applications, the framework predefines the command ID for the Cut command as ID_EDIT_CUT. For a list of all predefined command IDs, see the file AFXRES.H. For more information, see Standard Commands.

In addition, convention suggests a handler for the BN_CLICKED notification message from a button labeled “Use As Default” might be named

afx_msg void OnClickedUseAsDefault();

You might assign this command an ID of IDC_USE_AS_DEFAULT because it is equivalent to an application-specific user-interface object.

Both categories of messages take no arguments and return no value.


Handlers for Message-Map Ranges

Home | Overview | How Do I | Tutorial

This article explains how to map a range of messages to a single message handler function (instead of mapping one message to only one function).

There are times when you need to process more than one message or control notification in exactly the same way. At such times, you might wish to map all of the messages to a single handler function. Message-map ranges allow you to do this for a contiguous range of messages:

  • You can map ranges of command IDs to:
    • A command handler function.

    • A command update handler function.
  • You can map control-notification messages for a range of control IDs to a message handler function.

Topics covered in this article include:

  • Writing the message-map entry

  • Declaring the handler function

  • Example for a range of command IDs

  • Example for a range of control IDs

Important ClassWizard does not support message-map ranges, so you must write the message-map entries and handler function declarations yourself.

Writing the Message-Map Entry

In the .CPP file, add your message-map entry, as shown in the following example:

...
BEGIN_MESSAGE_MAP(CMyApp, CWinApp)
    //{{AFX_MSG_MAP(CMyApp)
    ...
    //}}AFX_MSG_MAP
ON_COMMAND_RANGE(ID_MYCMD_ONE, ID_MYCMD_TEN, OnDoSomething)
END_MESSAGE_MAP( )
...

The message-map entry consists of the following items:

  • The message-map range macro:
    • ON_COMMAND_RANGE

    • ON_UPDATE_COMMAND_UI_RANGE

    • ON_CONTROL_RANGE
  • Parameters to the macro:

    The first two macros take three parameters:

    • The command ID that starts the range

    • The command ID that ends the range

    • The name of the message handler function

    The range of command IDs must be contiguous.

    The third macro, ON_CONTROL_RANGE, takes an additional first parameter: a control-notification message, such as EN_CHANGE.

Declaring the Handler Function

In the .H file, add your handler function declaration outside the //{{AFX_MSG comment brackets. The following code shows how this might look, as shown in the next-to-last line below:

// Generated message-map functions
protected:
    //{{AFX_MSG(CMyApp)
        ...
    //}}AFX_MSG
    afx_msg void OnDoSomething( UINT nID );
    DECLARE_MESSAGE_MAP()

Handler functions for single commands normally take no parameters. With the exception of update handler functions, handler functions for message-map ranges require an extra parameter, nID, of type UINT. This parameter is the first parameter. The extra parameter accommodates the extra command ID needed to specify which command the user actually chose.

See Example for a Range of Command IDs for more information about parameter requirements for updating handler functions.

Example for a Range of Command IDs

When might you use ranges? One example is in handling commands like the Zoom command in the MFC sample HIERSVR. This command zooms the view, scaling it between 25% and 300% of its normal size. HIERSVR’s view class uses a range to handle the Zoom commands with a message-map entry resembling this:

ON_COMMAND_RANGE(ID_VIEW_ZOOM25, ID_VIEW_ZOOM300, OnZoom)

When you write the message-map entry, you specify:

  • Two command IDs, beginning and ending a contiguous range.

    Here they are ID_VIEW_ZOOM25 and ID_VIEW_ZOOM300.

  • The name of the handler function for the commands.

    Here it’s OnZoom.

The function declaration would resemble this:

afx_msg void OnZoom(UINT nID);

The case of update handler functions is similar, and likely to be more widely useful. It’s quite common to write ON_UPDATE_COMMAND_UI handlers for a number of commands and find yourself writing, or copying, the same code over and over. The solution is to map a range of command IDs to one update handler function using the ON_UPDATE_COMMAND_UI_RANGE macro. The command IDs must form a contiguous range. For an example, see the OnUpdateZoom handler and its ON_UPDATE_COMMAND_UI_RANGE message-map entry in the HIERSVR sample’s view class.

Update handler functions for single commands normally take a single parameter, pCmdUI, of type CCmdUI*. Unlike handler functions, update handler functions for message-map ranges do not require an extra parameter, nID, of type UINT. The command ID, which is needed to specify which command the user actually chose, is found in the CCmdUI object.

Example for a Range of Control IDs

Another interesting case is mapping control-notification messages for a range of control IDs to a single handler. Suppose the user can click any of 10 buttons. To map all 10 buttons to one handler, your message-map entry would look like this:

ON_CONTROL_RANGE(BN_CLICKED, IDC_BUTTON1, IDC_BUTTON10, OnButtonClicked)

When you write the ON_CONTROL_RANGE macro in your message map, you specify:

  • A particular control-notification message.

    Here it’s BN_CLICKED.

  • The control ID values associated with the contiguous range of controls.

    Here these are IDC_BUTTON1 and IDC_BUTTON10.

  • The name of the message handler function.

    Here it’s OnButtonClicked.

When you write the handler function, specify the extra UINT parameter, as shown in the following:

...
void CMyDialog::OnButtonClicked( UINT nID )
{
    int nButton = nID - IDC_BUTTON1;
    ASSERT( nButton >= 0 && nButton < 10 );
    // ...
}

The OnButtonClicked handler for a single BN_CLICKED message takes no parameters. The same handler for a range of buttons takes one UINT. The extra parameter allows for identifying the particular control responsible for generating the BN_CLICKED message.

The code shown in the example is typical: converting the value passed to an int within the message range and asserting that this is the case. Then you might take some different action depending on which button was clicked.


Handling Reflected Messages

Message reflection lets you handle messages for a control, such as WM_CTLCOLOR, WM_COMMAND, and WM_NOTIFY, within the control itself. This makes the control more self-contained and portable. The mechanism works with Windows common controls as well as with ActiveX controls (formerly called OLE controls).

Message reflection lets you reuse your CWnd-derived classes more readily. Message reflection works via CWnd::OnChildNotify, using special ON_XXX_REFLECT message map entries: for example, ON_CTLCOLOR_REFLECT and ON_CONTROL_REFLECT. Technical Note 62 explains message reflection in more detail.

What do you want to do?

  • Learn more about message reflection

  • Implement message reflection for a common control

  • Implement message reflection for an ActiveX control


How to Manage Commands and Messages with ClassWizard

Home | Overview | How Do I | Tutorial

ClassWizard is a tool is designed specifically to connect Windows messages and user-interface objects such as menus to their handlers.

The typical development scenarios are as follows:

  • You determine that one of your classes must handle a certain Windows message, so you run ClassWizard and make the connection.

  • You create a menu or accelerator resource, then invoke ClassWizard to connect the command associated with that object to a handler.

As you work with the framework, you’ll find that ClassWizard greatly simplifies your message-management tasks.

ClassWizard writes the following information to your source files:

  • The appropriate message-map entry for the connection

  • A declaration of the handler as a member function of the class

  • An empty function template for you to fill in with the handler’s code

For detailed information about using ClassWizard to connect messages to handlers, see Working with Classes Topics. For examples, see the tutorials Binding Visual Objects to Code Using WizardBar and Adding a Dialog Box.

Important Use ClassWizard to create and edit all message-map entries. If you add them manually, you may not be able to edit them with ClassWizard later. If you add them outside the bracketing comments //{{AFX_MSG_MAP(classname) and //}}AFX_MSG_MAP, ClassWizard cannot edit them at all. Note that by the same token ClassWizard will not touch any entries you add outside the comments, so feel free to add messages outside the comments if you do not want them to be modified. Some messages, such as message-map ranges, must be added outside the comments.


How to Display Command Information in the Status Bar

Home | Overview | How Do I | Tutorial

When you run AppWizard to create the skeleton of your application, you can easily support a toolbar and a status bar. A single option in AppWizard supports both. When a status bar is present, the framework automatically provides helpful feedback as the user of your application moves the mouse through items in the menus. The framework automatically displays a prompt string in the status bar when the menu item is being selected. For example, when the user drags the mouse over the Cut item on the Edit menu, the framework might display “Cut the selection and put it on the Clipboard” in the message area of the status bar. The prompt helps the user understand the menu item’s purpose. This also works when the user clicks a toolbar button.

You can easily add to this status-bar help by defining prompt strings for the menu items that you add to the program. To do so, provide the prompt strings when you edit the properties of the menu item in the menu editor. The strings you define this way are stored in your application’s resource file; they have the same IDs as the commands they explain.

By default, AppWizard adds the ID for a standard prompt, “Ready,” which is displayed when the program is waiting for new messages. If you specify the Context-Sensitive Help option in AppWizard, the ID for a help prompt, “For Help, press F1,” is added to your application. This ID is AFX_IDS_IDLEMESSAGE.


MFC Topics (General)

Home | Overview | How Do I | Sample | Tutorial

This family of articles includes technical details about the Microsoft Foundation Class Library (MFC) and provides an overview of the MFC framework and its key components and subsystems. MFC and the Active Template Library (ATL) are part of Microsoft Foundation Classes and Templates.

Technical details include:

  • How to use the MFC source files, which are supplied with Visual C++

  • How to use MFC.BSC, the MFC browse information file

  • MFC library versions

  • Managing the state data of MFC modules

  • Idle loop processing in MFC

What do you want to know more about?

  • Using MFC to write Windows programs

  • Building on the MFC framework

  • How the framework calls my code

  • CWinApp: the application class

  • Document templates and the document/view creation process

  • Creating windows of my own with class CWnd

  • Working with window objects

  • Working with Windows device contexts

  • Working with Windows graphic objects: pens, brushes, fonts, bitmaps, palettes, and regions

For information about many other aspects of MFC, see MFC: Overview. For an overview of the MFC reference documentation, see Microsoft Foundation Class Library.

For information about ATL, see Active Template Library Reference.


MFC: Using the MFC Source Files

Home | Overview | How Do I | Sample | Tutorial

The Microsoft Foundation Class Library (MFC) supplies full source code. Header files (.H) are in the MFC\Include directory; implementation files (.Cpp) are in the MFC\Src directory.

Note The MFC\Src directory contains a makefile you can use with NMake to build MFC library versions, including a browse version. A browse version of MFC is useful for tracing through the calling structure of MFC itself. The file Readme.Txt in that directory explains how to use this makefile.

This family of articles explains the conventions that MFC uses to comment the various parts of each class, what these comments mean, and what you should expect to find in each section. ClassWizard and AppWizard use similar conventions for the classes they create for you, and you will probably find these conventions useful for your own code.

You might be familiar with the public, protected, and private C++ keywords. When looking at the MFC header files, you'll find that each class may have several of each of these. For example, public member variables and functions might be under more than one public keyword. This is because MFC separates member variables and functions based on their use, not by the type of access allowed. MFC uses private sparingly — even items considered implementation details are generally protected and many times are public. Although access to the implementation details is discouraged, MFC leaves the decision to you.

In both the MFC source files and the files that AppWizard creates, you will find comments like these within class declarations (usually in this order):

// Constructors
// Attributes
// Operations
// Overridables
// Implementation

Topics covered in this family of articles include:

  • An example of the comments

  • The // Implementation comment

  • The // Constructors comment

  • The // Attributes comment

  • The // Operations comment

  • The // Overridables comment


An Example of the Comments

Home | Overview | How Do I | Sample | Tutorial

The following partial listing of class CStdioFile uses most of the standard comments that MFC employs in its classes to divide class members by the ways they are used:

class CStdioFile : public CFile
{
    DECLARE_DYNAMIC(CStdioFile)

public:
// Constructors
    CStdioFile();
...

// Attributes
    FILE* m_pStream;    // stdio FILE
...

// Operations
    virtual void WriteString(LPCTSTR lpsz);
...
    virtual LPTSTR ReadString(LPTSTR lpsz, UINT nMax);
...

// Implementation
public:
...
};

These comments consistently mark sections of the class declaration that contain similar kinds of class members. Keep in mind that these are MFC conventions, not set rules.

What do you want to know more about?

  • The // Implementation comment

  • The // Constructors comment

  • The // Attributes comment

  • The // Operations comment

  • The // Overridables comment


The // Implementation Comment

Home | Overview | How Do I | Sample | Tutorial

The // Implementation section is the most important part of any MFC class declaration.

This section houses all implementation details. Both member variables and member functions can appear in this section. Everything below this line could change in a future release of MFC. Unless you can't avoid it, you should not rely on details below the // Implementation line. In addition, members declared below the implementation line are not documented, although some implementation is discussed in technical notes. Overrides of virtual functions in the base class reside in this section, regardless of which section the base class function is defined in, because the fact that a function overrides the base class implementation is considered an implementation detail. Typically these members are protected, but not always.

Notice from the CStdioFile listing under An Example of the Comments that members declared below the // Implementation comment may be declared as public, protected, or private. You should only use these members with caution, because they might change in the future. Declaring a group of members as public may be necessary for the class library implementation to work correctly. However, this does not mean that you may safely use the members so declared.

Note You may find comments of the remaining types either above or below the // Implementation comment. In either case, they describe the kinds of members declared below them. If they occur below the // Implementation comment, you should assume that the members might change in future versions of MFC.

What do you want to know more about?

  • An example of the comments

  • The // Constructors comment

  • The // Attributes comment

  • The // Operations comment

  • The // Overridables comment


The // Constructors Comment

Home | Overview | How Do I | Sample | Tutorial

The // Constructors section of an MFC class declaration declares constructors (in the C++ sense) as well as any initialization functions required to really use the object. For example, CWnd::Create is in the constructors section because before you use the CWnd object it must be "fully constructed" by first calling the C++ constructor and then calling the Create function. Typically these members are public.

For example, class CStdioFile has three constructors, one of which is shown in the listing under An Example of the Comments.

What do you want to know more about?

  • The // Implementation comment

  • The // Attributes comment

  • The // Operations comment

  • The // Overridables comment


The // Attributes Comment

Home | Overview | How Do I | Sample | Tutorial

The // Attributes section of an MFC class declaration contains the public attributes (or properties) of the object. Typically these are member variables, or Get/Set functions. The "Get" and "Set" functions may or may not be virtual. The "Get" functions are usually const, because in most cases they don't have side effects. These members are normally public; protected and private attributes are typically found in the implementation section.

In the sample listing from class CStdioFile, under An Example of the Comments, the list includes one member variable, m_pStream. Class CDC lists nearly 20 members under this comment.

Note Large classes, such as CDC and CWnd, may have so many members that simply listing all of the attributes in one group would not add much to clarity. In such cases, the class library uses other comments as headings to further delineate the members. For example, CDC uses // Device-Context Functions, // Drawing Tool Functions, // Drawing Attribute Functions, and more. Groups that represent attributes will follow the usual syntax described above. Many of the OLE classes have an implementation section called // Interface Maps.

What do you want to know more about?

  • An example of the comments

  • The // Implementation comment

  • The // Constructors comment

  • The // Operations comment

  • The // Overridables comment


The // Operations Comment

Home | Overview | How Do I | Sample | Tutorial

The // Operations section of an MFC class declaration contains member functions that you can call on the object to make it do things or perform actions (perform operations). These functions are typically non-const since they usually have side effects. They may be virtual or nonvirtual depending on the needs of the class. Typically these members are public.

In the sample listing from class CStdioFile, under An Example of the Comments, the list includes two member functions under this comment: ReadString and WriteString.

As with attributes, operations may be further subdivided.

What do you want to know more about?

  • An example of the comments

  • The // Implementation comment

  • The // Constructors comment

  • The // Attributes comment

  • The // Overridables comment


The // Overridables Comment

Home | Overview | How Do I | Sample | Tutorial

The // Overridables section of an MFC class declaration contains virtual functions that you can override in a derived class when you need to modify the base class behavior. They are usually named starting with "On", although it is not strictly necessary. Functions here are designed to be overridden, and often implement or provide some sort of "callback" or "hook." Typically these members are protected.

In MFC itself, pure virtual functions are always placed in this section. A pure virtual function in C++ is one of the form:

virtual void OnDraw( ) = 0;

In the sample listing from class CStdioFile, under An Example of the Comments, the list includes no overridables section. Class CDocument, on the other hand, lists approximately 10 overridable member functions.

In some classes, you may also see the comment // Advanced Overridables. These are functions that only advanced programmers should attempt to override. You will probably never need to override them.

Note The conventions described in this article also work well, in general, for Automation (formerly known as OLE Automation) methods and properties. Automation methods are similar to MFC operations. Automation properties are similar to MFC attributes. Automation events (supported for ActiveX controls, formerly known as OLE controls) are similar to MFC overridable member functions.

What do you want to know more about?

  • An example of the comments

  • The // Implementation comment

  • The // Constructors comment

  • The // Attributes comment

  • The // Operations comment


MFC: Using the MFC Browse Information File

Home | Overview | How Do I | Sample | Tutorial

MFC.Bsc is the browse information file for the Microsoft Foundation Class Library. Use it to quickly look through the MFC source code for debugging purposes or to get a better idea of what's going on behind the scenes.

Not all MFC classes and symbols are included in the browse info file. For example, the ISAPI classes are not included because they are in a separate library. If you want to take a look at symbols that are not in the browse file, the Find In Files command on the File menu is another good way of locating items.

MFC.BSC is not installed by the setup program, but can be copied manually from the distribution disk. From the root CD directory, the path is \Program Files\Microsoft Visual Studio\VC98\MFC\Src\MFC.Bsc. Copy this file to the same directory on your hard disk where Visual C++ is installed. Once installed, the file can be opened and used the same as any other browse information file.

What do you want to know more about?

  • How do I open and browse the browser information file?

  • How do I modify my browse window display?

  • How do I browse through my classes, functions, or definitions and references?

  • What are the advantages and disadvantages of using browse information?

  • How do I disable or enable the browser information file?


MFC Library Versions

Home | Overview | How Do I | Sample | Tutorial

This article provides information on available versions of the Microsoft Foundation Class Library (MFC). Topics covered include:

  • Automatic linking of MFC library version

  • Library naming conventions

  • AFXDLL versions

  • Dynamic-Link Library (DLL) support


Automatic Linking of MFC Library Version

Home | Overview | How Do I | Sample | Tutorial

In versions of MFC prior to version 3.0 (prior to Visual C++ version 2.0), you had to manually specify the correct version of the MFC library in the input list of libraries for the linker. With MFC version 3.0 and later, it is no longer necessary to manually specify the version of the MFC library. Instead, the MFC header files automatically determine the correct version of the MFC library, based on values defined with #define, such as _DEBUG or _UNICODE. The MFC header files add "/defaultlib" directives instructing the linker to link in a specific version of the MFC library.

For example, the following code fragment from the AFX.H header file instructs the linker to link in either the NAFXCWD.LIB or NAFXCW.LIB version of MFC, depending on whether you are using the debug version of MFC:

...
#ifndef _UNICODE
    #ifdef _DEBUG
        #pragma comment(lib, "nafxcwd.lib")
    #else
        #pragma comment(lib, "nafxcw.lib")
    #endif
#else
    #ifdef _DEBUG
        #pragma comment(lib, "uafxcwd.lib")
    #else
        #pragma comment(lib, "uafxcw.lib")
    #endif
#endif...

MFC header files also link in all required libraries, including MFC libraries, Win32 libraries, OLE libraries, OLE libraries built from samples, ODBC libraries, and so on. The Win32 libraries include Kernel32.Lib, User32.Lib, and GDI32.Lib.


Library Naming Conventions

Home | Overview | How Do I | Sample | Tutorial

Object-code libraries for MFC use the following naming conventions. The library names have the form

uAFXcWd.LIB

where the letters shown in italic lowercase are placeholders for specifiers whose meanings are shown in the table Library Naming Conventions below:

Library Naming Conventions

Specifier | Values and Meanings
u | ANSI (N) or Unicode (U)
c | Type of program to create: C=all
d | Debug or Release: D=Debug; omit specifier for Release

The default is to build a debug Windows ANSI application for the Intel® platform: NAFXCWD.Lib. All libraries — listed in the table Static Library Versions below — are included prebuilt in the MFC\Lib directory on the Visual C++ CD-ROM.

Static Library Versions

Library | Description
NAFXCW.LIB | Release version
NAFXCWD.LIB | Debug version (default)
UAFXCW.LIB | Release version with Unicode support
UAFXCWD.LIB | Debug version with Unicode support

Note If you need to build a library version, see the Readme.Txt file in the \MFC\Src directory. This file describes using the supplied makefile with NMake.

What do you want to know more about?

  • Naming Conventions for MFC DLLs

  • Redistributable files

  • Categories of redistributable files

  • Unicode versions of the MFC libraries


AFXDLL Versions

Home | Overview | How Do I | Sample | Tutorial

Instead of building your application by statically linking to the MFC object-code libraries, you can build your application to use one of the AFXDLL libraries — which contain MFC in a DLL that multiple running applications can share. For a table of AFXDLL names, see the article DLLs: Naming Conventions.

Note By default, AppWizard creates an AFXDLL project. To use static linking of MFC code instead, set the Use MFC in a static library option in AppWizard. Static linking is not available in the Standard Edition of Visual C++.


Dynamic-Link Library Support

Home | Overview | How Do I | Sample | Tutorial

The NAFXDWD.Lib and NAFXDW.Lib libraries create your project as a dynamic-link library, called a "Regular DLL," (formerly a "USRDLL") that can be used with applications not built with the class library. Don't confuse this DLL support with MFCx0.DLL and MFCx0D.DLL (known as AFXDLL), which contain the entire 32-bit class library in a DLL. For more information, see DLLs: Overview. For a table of DLL names, see the article DLLs: Naming Conventions.


Using the Classes to Write Applications for Windows

Home | Overview | How Do I | Sample | Tutorial

Taken together, the classes in the Microsoft Foundation Class Library (MFC) make up an "application framework" — the framework on which you build an application for Windows. At a very general level, the framework defines the skeleton of an application and supplies standard user-interface implementations that can be placed onto the skeleton. Your job as programmer is to fill in the rest of the skeleton — those things that are specific to your application. You can get a head start by using AppWizard to create the files for a very thorough starter application. You use the Microsoft Visual C++™ resource editors to design your user-interface elements visually, ClassWizard to connect those elements to code, and the class library to implement your application-specific logic.

Version 3.0 and later of the MFC framework supports 32-bit programming for Win32 platforms, including Microsoft Windows 95 and Microsoft Windows NT version 3.51 and later. MFC Win32 support includes multithreading. Use version 1.5x if you need to do 16-bit programming.

This family of articles presents a broad overview of the application framework. It also explores the major objects that make up your application and how they are created. Among the topics covered in these articles are the following:

  • The framework

  • Division of labor between the framework and your code, as described in Building on the Framework

  • The application class, which encapsulates application-level functionality

  • How document templates create and manage documents and their associated views and frame windows

  • Class CWnd, the root base class of all windows

  • Graphic objects, such as pens and brushes

Other parts of the framework story include:

  • MFC: Overview

  • Window Objects: Overview

  • Messages and Commands: Overview

  • CObject, The Root Base Class in MFC: Overview

  • Document/View Architecture: Overview

  • Dialog Boxes: Overview

  • Controls: Overview

  • Control Bars: Overview

  • OLE in MFC: Overview

  • Memory Management with MFC: Overview

    Besides giving you a considerable head start in writing applications for Windows, MFC also makes it much easier to write applications that specifically use OLE linking and embedding technology. You can make your application an OLE visual editing container, an OLE visual editing server, or both, and you can add Automation so that other applications can use objects from your application or even drive it remotely.

  • Developing ActiveX Controls

    The OLE control development kit (CDK) is now fully integrated with the framework. This article family supplies an overview of ActiveX control development with MFC. (ActiveX controls were formerly known as OLE controls.)

  • Database Topics

    MFC also supplies two sets of database classes that simplify writing data-access applications. Using the ODBC database classes, you can connect to databases via an Open Database Connectivity (ODBC) driver, select records from tables, and display record information in an on-screen form. Using the Data Access Object (DAO) classes, you can work with databases via the Microsoft Jet database engine or external (non-Jet) data sources, including ODBC data sources.

    In addition, MFC is fully enabled for writing applications that use Unicode™ and multibyte character sets (MBCS), specifically double-byte character sets (DBCS).

For a step-by-step tutorial in which you build an application with the framework, read the Scribble Tutorial.

For a general guide to MFC documentation, see the topic MFC: Overview.


The Framework

Home | Overview | How Do I | Sample | Tutorial

Your work with the Microsoft Foundation Class Library (MFC) framework is based largely on a few major classes and several Visual C++ tools. Some of the classes encapsulate a large portion of the Win32 application programming interface (API). Other classes encapsulate application concepts such as documents, views, and the application itself. Still others encapsulate OLE features and ODBC and DAO data-access functionality.

For example, Win32's concept of window is encapsulated by MFC class CWnd. That is, a C++ class called CWnd encapsulates or "wraps" the HWND handle that represents a Windows window. Likewise, class CDialog encapsulates Win32 dialog boxes.

Encapsulation means that the C++ class CWnd, for example, contains a member variable of type HWND, and the class's member functions encapsulate calls to Win32 functions that take an HWND as a parameter. The class member functions typically have the same name as the Win32 function they encapsulate.

What do you want to know more about?

  • SDI and MDI

  • Documents, views, and the framework

  • Wizards, WizardBar, and resource editors

  • Building on the framework

  • How the framework calls my code

  • CWinApp: the application class

  • Document templates and the document/view creation process

  • Messages and commands

  • Windows


SDI and MDI

Home | Overview | How Do I | Sample | Tutorial

MFC makes it easy to work with both single document interface (SDI) and multiple document interface (MDI) applications.

SDI applications allow only one open document frame window at a time. MDI applications allow multiple document frame windows to be open in the same instance of an application. An MDI application has a window within which multiple MDI child windows, which are frame windows themselves, can be opened, each containing a separate document. In some applications, the child windows can be of different types, such as chart windows and spreadsheet windows. In that case, the menu bar can change as MDI child windows of different types are activated.

Note Under Windows 95, applications are commonly SDI because the operating system has adopted a "document-centered" view.

What do you want to know more about?

  • Documents, views, and the framework


Documents, Views, and the Framework

Home | Overview | How Do I | Sample | Tutorial

At the heart of the MFC framework are the concepts of document and view. A document is a data object with which the user interacts in an editing session. It is created by the New or Open command on the File menu and is typically saved in a file. (Don't confuse standard MFC documents, derived from class CDocument, with Active documents or OLE compound documents.) A view is a window object through which the user interacts with a document.

The key objects in a running application are:

  • The document(s)

    Your document class (derived from CDocument) specifies your application's data.

    If you want OLE functionality in your application, derive your document class from COleDocument or one of its derived classes, depending on the type of functionality you need.

  • The view(s)

    Your view class (derived from CView) is the user's "window on the data." The view class controls how the user sees your document's data and interacts with it. In some cases, you may want a document to have multiple views of the data.

    If you need scrolling, derive from CScrollView. If your view has a user interface that is laid out in a dialog-template resource, derive from CFormView. For simple text data, use or derive from CEditView. For a form-based data-access application, such as a data-entry program, derive from CRecordView (for ODBC) or CDaoRecordView (for DAO). Also available are classes CTreeView, CListView, and CRichEditView.

  • The frame windows

    Views are displayed inside "document frame windows." In an SDI application, the document frame window is also the "main frame window" for the application. In an MDI application, document windows are child windows displayed inside a main frame window. Your derived main frame-window class specifies the styles and other characteristics of the frame windows that contain your views. If you need to customize frame windows, derive from CFrameWnd to customize the document frame window for SDI applications. Derive from CMDIFrameWnd to customize the main frame window for MDI applications. Also derive a class from CMDIChildWnd to customize each of the distinct kinds of MDI document frame windows that your application supports.

  • The document template(s)

    A document template orchestrates the creation of documents, views, and frame windows. A particular document-template class, derived from class CDocTemplate, creates and manages all open documents of one type. Applications that support more than one type of document have multiple document templates. Use class CSingleDocTemplate for SDI applications, or use class CMultiDocTemplate for MDI applications.

  • The application object

    Your application class (derived from CWinApp) controls all of the objects above and specifies application behavior such as initialization and cleanup. The application's one and only application object creates and manages the document templates for any document types the application supports.

  • Thread objects

    If your application creates separate threads of execution — for example, to perform calculations in the background — you'll use classes derived from CWinThread. CWinApp itself is derived from CWinThread and represents the primary thread of execution (or the main process) in your application. You can also use MFC in secondary threads.

In a running application, these objects cooperatively respond to user actions, bound together by commands and other messages. A single application object manages one or more document templates. Each document template creates and manages one or more documents (depending on whether the application is SDI or MDI). The user views and manipulates a document through a view contained inside a frame window. The figure Objects in a Running SDI Application below shows the relationships among these objects for an SDI application.

Objects in a Running SDI Application

The rest of this family of articles explains how the framework tools, AppWizard, ClassWizard, WizardBar, and the resource editors, create these objects, how they work together, and how you use them in your programming. Documents, views, and frame windows are discussed in more detail in Window Objects: Overview and Document/View Architecture: Overview.


AppWizard, ClassWizard, and the Resource Editors

Home | Overview | How Do I | Sample | Tutorial

Visual C++ includes several wizards and the WizardBar for use in MFC programming, along with many integrated resource editors. For ActiveX controls programming, the ActiveX ControlWizard serves a purpose much like that of AppWizard. While you can write MFC applications without most of these tools, the tools greatly simplify and speed your work.

Use AppWizard to Create an MFC Application

Use AppWizard to create an MFC project in Visual C++ — which can include OLE and database support. Files in the project contain your application, document, view, and frame-window classes; standard resources, including menus and an optional toolbar; other required Windows files; and optional .RTF files containing standard Windows Help topics that you can revise and add to in order to create your program's help file.

Use ClassWizard to Manage Classes and Windows Messages

ClassWizard helps you create handler functions for Windows messages and commands, create and manage classes, create class member variables, create Automation methods and properties, create database classes, and more.

Tip ClassWizard also helps you to override virtual functions in the MFC classes. Select the class and the virtual function to override. The rest of the process is similar to message handling, as described in the following paragraphs.

Applications running under Windows are message driven. User actions and other events that occur in the running program cause Windows to send messages to the windows in the program. For example, if the user clicks the mouse in a window, Windows sends a WM_LBUTTONDOWN message when the left mouse button is pressed and a WM_LBUTTONUP message when the button is released. Windows also sends WM_COMMAND messages when the user selects commands from the menu bar.

In the MFC framework, various objects — documents, views, frame windows, document templates, the application object — can "handle" messages. Such an object provides a "handler function" as one of its member functions, and the framework maps the incoming message to its handler.

A large part of your programming task is choosing which messages to map to which objects and then implementing that mapping. To do so, you use ClassWizard.

ClassWizard will create empty message-handler member functions, and you use the source code editor to implement the body of the handler.

Quick access to frequently used features of ClassWizard are available at any time in the WizardBar, and you can create or edit classes (including classes of your own, not derived from MFC classes) and their members with ClassView.

Use the Resource Editors to Create and Edit Resources

Use the Visual C++ resource editors to create and edit menus, dialog boxes, custom controls, accelerator keys, bitmaps, icons, cursors, strings, and version resources. ClassWizard works with the editors: for example, when you create a dialog-template resource, you can run ClassWizard to connect the resource to a dialog class. As of Visual C++ version 4.0, a toolbar editor makes creating toolbars much easier.

To help you even more, the Microsoft Foundation Class Library provides a file called COMMON.RES, which contains "clip art" resources that you can copy from COMMON.RES and paste into your own resource file. COMMON.RES includes toolbar buttons, common cursors, icons, and more. You can use, modify, and redistribute these resources in your application. For more information about COMMON.RES, see the article COMMON.RES Sample Resources.

As you can see, AppWizard, the Visual C++ resource editors, ClassWizard, WizardBar, ClassView, and the MFC framework do a lot of work for you and make managing your code much easier. The bulk of your application-specific code is in your document and view classes. For a list of tutorials you can try, see MFC Tutorials Available.


Building on the Framework

Home | Overview | How Do I | Sample | Tutorial

Your role in configuring an application with the MFC framework is to supply the application-specific source code and to connect the components by defining what messages and commands they respond to. You use the C++ language and standard C++ techniques to derive your own application-specific classes from those supplied by the class library and to override and augment the base class's behavior.

For a list of tutorials you can work through, see MFC Tutorials Available.

In related topics, the following tables describe the general sequence of operations you will typically follow and your responsibilities vs. the framework's responsibilities:

  • Sequence for Building an Application with the Framework

  • Sequence for Creating OLE Applications

  • Sequence for Creating ActiveX Controls

  • Sequence for Creating Database Applications

For the most part, you can follow these tables as a sequence of steps for creating an MFC application, although some of the steps are alternative options. For example, most applications use one type of view class from the several types available.


Sequence of Operations for Building MFC Applications

Home | Overview | How Do I | Sample | Tutorial

The following table explains the general sequence you might typically follow as you develop your MFC application.

Sequence for Building an Application with the Framework

Task | You do | The framework does
Create a skeleton application. | Run AppWizard. Specify the options you want in the options pages. Options include making the application a COM component, container, or both; adding Automation; and making the application database-aware. | AppWizard creates the files for a skeleton application, including source files for your application, document, view, and frame windows; a resource file; a project file; and others — all tailored to your specifications.
See what the framework and AppWizard offer without adding a line of your own code. | Build the skeleton application and run it in Visual C++. | The running skeleton application derives many standard File, Edit, View, and Help menu commands from the framework. For MDI applications, you also get a fully functional Window menu, and the framework manages creation, arrangement, and destruction of MDI child windows.
Construct your application's user interface. Use the Visual C++ resource editors to visually edit the application's user interface:
  • Create menus.

  • Define accelerators.

  • Create dialog boxes.

  • Create and edit bitmaps, icons, and cursors.

  • Edit the toolbar created for you by AppWizard.

  • Create and edit other resources.

You can also test the dialog boxes in the dialog editor.

 The default resource file created by AppWizard supplies many of the resources you need. Visual C++ lets you edit existing resources and add new resources easily and visually.
Map menus to handler functions. | Use ClassWizard or WizardBar to connect menus and accelerators to handler functions in your code. | ClassWizard or WizardBar inserts message-map entries and empty function templates into the source files you specify and manages many manual coding tasks.
Write your handler code. | Use ClassWizard or ClassView in the Project Workspace window to jump directly to the code in the source code editor. Fill in the code for your handler functions. | ClassWizard brings up the editor, scrolls to the empty function template, and positions the cursor for you.
Map toolbar buttons to commands. | Map each button on your toolbar to a menu or accelerator command by assigning the button the appropriate command ID. | The framework controls the drawing, enabling, disabling, checking, and other visual aspects of the toolbar buttons.
Test your handler functions. | Rebuild the program and use the built-in debugging tools to test that your handlers work correctly. | You can step or trace through the code to see how your handlers are called. If you've filled out the handler code, the handlers carry out commands. The framework will automatically disable menu items and toolbar buttons that are not handled.
Add dialog boxes. | Design dialog-template resources with the dialog editor. Then use ClassWizard to create a dialog class and the code that handles the dialog box. | The framework manages the dialog box and facilitates retrieving information entered by the user.
Initialize, validate, and retrieve dialog-box data. | You can also define how the dialog box's controls are to be initialized and validated. Use ClassWizard to add member variables to the dialog class and map them to dialog controls. Specify validation rules to be applied to each control as the user enters data. Provide your own custom validations if you wish. | The framework manages dialog-box initialization and validation. If the user enters invalid information, the framework displays a message box and lets the user reenter the data.
Create additional classes. | Use ClassWizard, WizardBar, or ClassView to create additional document, view, and frame-window classes beyond those created automatically by AppWizard. You can create additional database recordset classes, dialog classes, and so on. (With ClassView, you can create classes not derived from MFC classes.) | ClassWizard adds these classes to your source files and helps you define their connections to any commands they handle.
Add ready-to-use components to your application. | Use the Gallery to add a variety of components. | These components are easy to integrate into your application and save you a great deal of work.
Implement your document class. | Implement your application-specific document class(es). Add member variables to hold data structures. Add member functions to provide an interface to the data. | The framework already knows how to interact with document data files. It can open and close document files, read and write the document's data, and handle other user interfaces. You can focus on how the document's data is manipulated.
Implement Open, Save, and Save As commands. | Write code for the document's Serialize member function. | The framework displays dialog boxes for the Open, Save, and Save As commands on the File menu. It writes and reads back a document using the data format specified in your Serialize member function.
Implement your view class. | Implement one or more view classes corresponding to your documents. Implement the view's member functions that you mapped to the user interface with ClassWizard. A variety of CView-derived classes are available, including CListView and CTreeView. | The framework manages most of the relationship between a document and its view. The view's member functions access the view's document to render its image on the screen or printed page and to update the document's data structures in response to user editing commands.
Enhance default printing. | If you need to support multipage printing, override view member functions. | The framework supports the Print, Print Setup, and Print Preview commands on the File menu. You must tell it how to break your document into multiple pages.
Add scrolling. | If you need to support scrolling, derive your view class(es) from CScrollView. | The view automatically adds scroll bars when the view window becomes too small.
Create form views. | If you want to base your views on dialog-template resources, derive your view class(es) from CFormView. | The view uses the dialog-template resource to display controls. The user can tab from control to control in the view.
Create database forms. | If you want a form-based data-access application, derive your view class from CRecordView (for ODBC programming) or CDaoRecordView (for DAO programming). | The view works like a form view, but its controls are connected to the fields of a CRecordset or CDaoRecordset object representing a database table. MFC moves data between the controls and the recordset for you.
Create a simple text editor. | If you want your view to be a simple text editor, derive your view class(es) from CEditView or CRichEditView.. | The view provides editing functions, Clipboard support, and file input/output. CRichEditView provides styled text.
Add splitter windows. | If you want to support window splitting, add a CSplitterWnd object to your SDI frame window or MDI child window and hook it up in the window's OnCreateClient member function. | The framework supplies splitter-box controls next to the scroll bars and manages splitting your view into multiple panes. If the user splits a window, the framework creates and attaches additional view objects to the document.
Build, test, and debug your application. | Use the facilities of Visual C++ to build, test, and debug your application. | Visual C++ lets you adjust compile, link, and other options. It also lets you browse your source code and class structure.

What do you want to know more about?

  • Sequence of Operations for Creating OLE Applications

  • Sequence of Operations for Creating ActiveX Controls

  • Sequence of Operations for Creating Database Applications


Sequence of Operations for Creating OLE Applications

Home | Overview | How Do I | Sample | Tutorial

The following table shows your role and the framework's role in creating OLE linking and embedding applications. These represent options available rather than a sequence of steps to perform.

Creating OLE Applications

Task | You do | The framework does
Create a COM component. | Run AppWizard. Choose Full-server or Mini-server in compound document support. (From an existing application, emulate Step 7 in the Scribble tutorial.) | The framework generates a skeleton application with COM component capability enabled. All of the COM capability can be transferred to your existing application with only slight modification.
Create a container application from scratch. | Run AppWizard. Choose Container in compound document support. In ClassWizard, jump to the source code editor. Fill in code for your COM handler functions. | The framework generates a skeleton application that can insert COM objects created by COM component (server) applications.
Create an application that supports Automation from scratch. | Run AppWizard. Choose Automation support in step 3. Use ClassWizard to expose methods and properties in your application for automation. | The framework generates a skeleton application that can be activated and automated by other applications.

What do you want to know more about?

  • Sequence of Operations for Building MFC Applications

  • Sequence of Operations for Creating ActiveX Controls

  • Sequence of Operations for Creating Database Applications


Sequence of Operations for Creating ActiveX Controls

Home | Overview | How Do I | Sample | Tutorial

The following table shows your role and the framework's role in creating ActiveX controls (formerly known as OLE controls).

Creating ActiveX Controls

Task | You do | The framework does
Create an ActiveX control framework. | Run a custom AppWizard, called ActiveX ControlWizard, to create your control. Specify the options you want in the options pages. Options include number of controls in the project, licensing, subclassing, and an About Box method. | AppWizard creates the files for an ActiveX control with basic functionality, including source files for your application, control, and property page(s); a resource file; a project file; and others — all tailored to your specifications.
See what the control and ActiveX ControlWizard offer without adding a line of your own code. | Build the ActiveX control and test it with Test Container. | The running control has the ability to be resized and moved. It also has an About Box method (if chosen) that can be invoked.
Implement the control's methods and properties. | Implement your control-specific methods and properties by adding member functions to provide an exposed interface to the control's data. Add member variables to hold data structures and use event handlers to fire events when you determine. | The framework has already defined a map to support the control's events, properties, and methods, leaving you to focus on how the properties and methods are implemented. The default property page is viewable and a default About Box method is supplied.
Construct the control's property page(s). Use the Visual C++ resource editors to visually edit the control's property page interface:
  • Create additional property pages.

  • Create and edit bitmaps, icons, and cursors.

You can also test the property page(s) in the dialog editor.

 The default resource file created by AppWizard supplies many of the resources you need. Visual C++ lets you edit existing resources and add new resources easily and visually.
Test the control's events, methods, and properties. | Rebuild the control and use Test Container to test that your handlers work correctly. | You can invoke the control's methods and manipulate its properties through the property page interface or through Test Container. In addition, use Test Container to track events fired from the control and notifications received by the control's container.

What do you want to know more about?

  • Sequence of Operations for Building MFC Applications

  • Sequence of Operations for Creating OLE Applications

  • Sequence of Operations for Creating Database Applications


Sequence of Operations for Creating Database Applications

Home | Overview | How Do I | Sample | Tutorial

The following table shows your role and the framework's role in writing database applications.

Creating Database Applications

Task | You do | The framework does
Decide whether to use the MFC DAO classes or the MFC ODBC classes. | See Should I use DAO or ODBC in Visual C++ Programmer's Guide. For general information, see the article Databases: Overview. | The framework supplies two sets of database classes, one based on Data Access Objects (DAO) and the Microsoft Jet database engine, and the other based on ODBC.
Create your skeleton application with database options. | Run AppWizard. Select options on the database options page. If you choose one of the options that creates a record view, also specify a data source and table name(s) and/or query name(s). | AppWizard creates files and specifies the necessary includes. Depending on whether you specify DAO or ODBC and which other options you specify, the files can include a recordset class.
Design your database form(s). | Use the Visual C++ dialog editor to place controls on the dialog template resources for your record view classes. | AppWizard creates an empty dialog template resource for you to fill in.
Create additional record view and recordset classes as needed. | Use ClassWizard to create the classes and the dialog editor to design the views. | ClassWizard creates additional files for your new classes.
Create recordset objects as needed in your code. Use each recordset to manipulate records. | Your recordsets are based on the classes derived from CRecordset or CDaoRecordset with the wizards. If you're using DAO, you can also use CDaoRecordset objects without deriving a class of your own. | The framework uses record field exchange (DFX for DAO, RFX for ODBC) to exchange data between the database and your recordset's field data members. If you're using a record view, dialog data exchange (DDX) exchanges data between the recordset and the controls on the record view.
Or create an explicit CDatabase or CDaoDatabase object in your code for each database you want to open. | Base your recordset objects on the database objects. | The database object provides an interface to the data source.
In DAO, access a "workspace." Use a CDaoWorkspace object to:
  • Access DAO's default workspace.

  • Manage a separate transaction space.

  • Access the Microsoft Jet database engine.
 The workspace lets you manage one or more open databases in a single transaction space.
In DAO, work with tables and perform data definition language (DDL) tasks. Use a CDaoTableDef object to:
  • Create a recordset.

  • Add a table.

  • Attach to an external data source, such as ODBC.

  • Examine table structure.

  • Add or delete fields and indexes and set other table properties.
In DAO, work with stored queries. Use a CDaoQueryDef object to:
  • Create a recordset.

  • Store a query.

  • Execute an action query or an SQL pass-through query.
Bind data columns to your recordset dynamically. | In DAO, use a CDaoRecordset object directly to set or get field and parameter values. See the article DAO Recordset: Binding Records Dynamically. In ODBC, add code to your derived recordset class to manage the binding. See the article Recordset: Dynamically Binding Data Columns (ODBC).
Work with data in external data sources, such as ODBC data sources (for which you need an ODBC driver, under either ODBC or DAO). A non-external data source is one you can open directly with the Microsoft Jet database engine. | In most cases with DAO, use CDaoTableDef objects to attach tables from the external data source rather than opening the data source directly.

If you have Visual C++ Enterprise Edition, you can also debug SQL stored procedures and triggers, view data graphically, design and execute queries, and design database schemas.

What do you want to know more about?

  • Sequence of Operations for Building MFC Applications

  • Sequence of Operations for Creating OLE Applications

  • Sequence of Operations for Creating ActiveX Controls


How the Framework Calls Your Code

Home | Overview | How Do I | Sample | Tutorial

It is crucial to understand the relationship between your source code and the code in the MFC framework. When your application runs, most of the flow of control resides in the framework's code. The framework manages the message loop that gets messages from Windows as the user chooses commands and edits data in a view. Events that the framework can handle by itself don't rely on your code at all. For example, the framework knows how to close windows and how to exit the application in response to user commands. As it handles these tasks, the framework uses message handlers and C++ virtual functions to give you opportunities to respond to these events as well. But your code is not in control, the framework is.

The framework calls your code for application-specific events. For example, when the user chooses a menu command, the framework routes the command along a sequence of C++ objects: the current view and frame window, the document associated with the view, the document's document template, and the application object. If one of these objects can handle the command, it does so, calling the appropriate message-handler function. For any given command, the code called may be yours or it may be the framework's.

This arrangement is somewhat familiar to programmers experienced with traditional programming for Windows or event-driven programming.

In related topics, you'll see what the framework does as it initializes and runs the application and then cleans up as the application terminates. You'll also get a clearer picture of where the code you write fits in.

What do you want to know more about?

  • Class CWinApp, the application class

  • Document templates and the document/view creation process


CWinApp: The Application Class

Home | Overview | How Do I | Sample | Tutorial

The main application class in MFC encapsulates the initialization, running, and termination of an application for Windows. An application built on the framework must have one (and only one) object of a class derived from CWinApp. This object is constructed before windows are created. (CWinApp is derived from CWinThread, which represents the main thread of execution for your application, which might have one or more threads. In recent versions of MFC, the InitInstance, Run, ExitInstance, and OnIdle member functions are actually in class CWinThread. These functions are discussed here as if they were CWinApp members instead, since the discussion concerns the object's role as application object rather than as primary thread.)

Note Your application class constitutes your application's primary thread of execution. Using Win32 API functions, you can also create secondary threads of execution. These threads can use the MFC library. For more information, see Multithreading Topics.

Like any program for Windows, your framework application has a WinMain function. In a framework application, however, you don't write WinMain. It is supplied by the class library and is called when the application starts up. WinMain performs standard services such as registering window classes. Then it calls member functions of the application object to initialize and run the application. (You can customize WinMain by overriding the CWinApp member functions that WinMain calls.)

To initialize the application, WinMain calls your application object's InitApplication and InitInstance member functions. To run the application's message loop, WinMain calls the Run member function. On termination, WinMain calls the application object's ExitInstance member function. The figure Sequence of Execution below shows the sequence of execution in a framework application.

Sequence of Execution

Note Names shown in bold type in this documentation indicate elements supplied by the Microsoft Foundation Class Library and Visual C++. Names shown in monospaced type indicate elements that you create or override.

What do you want to know more about?

  • CWinApp and AppWizard

  • Overridable CWinApp member functions

  • Special CWinApp services


CWinApp and AppWizard

Home | Overview | How Do I | Sample | Tutorial

When it creates a skeleton application, AppWizard declares an application class derived from CWinApp. AppWizard also generates an implementation file that contains the following items:

  • A message map for the application class

  • An empty class constructor

  • A variable that declares the one and only object of the class

  • A standard implementation of your InitInstance member function

The application class is placed in the project header and main source files. The names of the class and files created are based on the project name you supply in AppWizard. The easiest way to view the code for these classes is through the Class View in the Project Workspace window.

The standard implementations and message map supplied are adequate for many purposes, but you can modify them as needed. The most interesting of these implementations is the InitInstance member function. Typically you will add code to the skeletal implementation of InitInstance.

What do you want to know more about?

  • Overridable CWinApp member functions

  • Special CWinApp services


Overridable CWinApp Member Functions

Home | Overview | How Do I | Sample | Tutorial

CWinApp provides several key overridable member functions (CWinApp overrides these members from class CWinThread, from which CWinApp derives):

  • InitInstance

  • Run

  • ExitInstance

  • OnIdle

The only CWinApp member function that you must override is InitInstance.


InitInstance Member Function

Home | Overview | How Do I | Sample | Tutorial

Windows allows you to run more than one copy, or "instance," of the same application. WinMain calls InitInstance every time a new instance of the application starts.

The standard InitInstance implementation created by AppWizard performs the following tasks:

  • As its central action, creates the document templates that, in turn, create documents, views, and frame windows. For a description of this process, see Document Template Creation.

  • Loads standard file options from an .INI file or the Windows registry, including the names of the most recently used files.

  • Registers one or more document templates.

  • For an MDI application, creates a main frame window.

  • Processes the command line to open a document specified on the command line or to open a new, empty document.

You can add your own initialization code or modify the code written by the wizard.


Run Member Function

Home | Overview | How Do I | Sample | Tutorial

A framework application spends most of its time in the Run member function of class CWinApp. After initialization, WinMain calls Run to process the message loop.

Run cycles through a message loop, checking the message queue for available messages. If a message is available, Run dispatches it for action. If no messages are available — often the case — Run calls OnIdle to do any idle-time processing that you or the framework may need done. If there are no messages and no idle processing to do, the application waits until something happens. When the application terminates, Run calls ExitInstance. The figure The Message Loop in OnIdle Member Function shows the sequence of actions in the message loop.

Message dispatching depends on the kind of message. For more information, see Messages and Commands in the Framework.


ExitInstance Member Function

Home | Overview | How Do I | Sample | Tutorial

The ExitInstance member function of class CWinApp is called each time a copy of your application terminates, usually as a result of the user quitting the application.

Override ExitInstance if you need special cleanup processing, such as freeing graphics device interface (GDI) resources or deallocating memory used during program execution. Cleanup of standard items such as documents and views, however, is provided by the framework, with other overridable functions for doing special cleanup specific to those objects.


OnIdle Member Function

Home | Overview | How Do I | Sample | Tutorial

When no Windows messages are being processed, the framework calls the CWinApp member function OnIdle (described in the Class Library Reference).

Override OnIdle to perform background tasks. The default version updates the state of user-interface objects such as toolbar buttons and performs cleanup of temporary objects created by the framework in the course of its operations. The figure The Message Loop illustrates how the message loop calls OnIdle when there are no messages in the queue.

The Message Loop

For more information about what you can do in the idle loop, see Idle Loop Processing.


Special CWinApp Services

Home | Overview | How Do I | Sample | Tutorial

Besides running the message loop and giving you an opportunity to initialize the application and clean up after it, CWinApp provides several other services.

Shell Registration

By default, AppWizard makes it possible for the user to open data files that your application has created by double-clicking them in the Windows Explorer or File Manager. If your application is an MDI application and you specify an extension for the files your application creates, AppWizard adds calls to the RegisterShellFileTypes and EnableShellOpen member functions of CWinApp to the InitInstance override that it writes for you.

RegisterShellFileTypes registers your application's document types with Windows Explorer or File Manager. The function adds entries to the registration database that Windows maintains. The entries register each document type, associate a file extension with the file type, specify a command line to open the application, and specify a dynamic data exchange (DDE) command to open a document of that type.

EnableShellOpen completes the process by allowing your application to receive DDE commands from Windows Explorer or File Manager to open the file chosen by the user.

This automatic registration support in CWinApp eliminates the need to ship an .REG file with your application or to do special installation work.

File Manager Drag and Drop

Windows versions 3.1 and later allow the user to drag file names from the file view window in the File Manager (or Windows Explorer in Windows 95 and later and in Windows NT 4.0 and later) and drop them into a window in your application. You might, for example, allow the user to drag one or more filenames into an MDI application's main window, where the application could retrieve the file names and open MDI child windows for those files.

To enable file drag and drop in your application, AppWizard writes a call to the CWnd member function DragAcceptFiles for your main frame window in your InitInstance. You can remove that call if you do not want to implement the drag-and-drop feature.

Note You can also implement more general drag-and-drop capabilities — dragging data between or within documents — using OLE. For information, see the article Drag and Drop (OLE).

Keeping Track of the Most Recently Used Documents

As the user opens and closes files, the application object keeps track of the four most recently used files. The names of these files are added to the File menu and updated when they change. The framework stores these file names in either the registry or in the .INI file, with the same name as your project and reads them from the file when your application starts up. The InitInstance override that AppWizard creates for you includes a call to the CWinApp member function LoadStdProfileSettings, which loads information from the registry or .INI file, including the most recently used file names.

These entries are stored as follows:

  • In Windows NT, the value is stored to a registry key.

  • In Windows 3.x, the value is stored in the WIN.INI file.

  • In Windows 95, the value is stored in a cached version of WIN.INI.


Document Templates and the Document/View Creation Process

Home | Overview | How Do I | Sample | Tutorial

To manage the complex process of creating documents with their associated views and frame windows, the framework uses two document template classes: CSingleDocTemplate for SDI applications and CMultiDocTemplate for MDI applications. A CSingleDocTemplate can create and store one document of one type at a time. A CMultiDocTemplate keeps a list of many open documents of one type.

Some applications support multiple document types. For example, an application might support text documents and graphics documents. In such an application, when the user chooses the New command on the File menu, a dialog box shows a list of possible new document types to open. For each supported document type, the application uses a distinct document template object. The figure An MDI Application with Two Document Types illustrates the configuration of an MDI application that supports two document types. The following figure shows several open documents.

An MDI Application with Two Document Types

Document templates are created and maintained by the application object. One of the key tasks performed during your application's InitInstance function is to construct one or more document templates of the appropriate kind. This feature is described in Document Template Creation. The application object stores a pointer to each document template in its template list and provides an interface for adding document templates.

If you need to support two or more document types, you must add an extra call to AddDocTemplate for each document type.

An icon is registered for each document template based on its position in the application's list of document templates. The order of the document templates is determined by the order they are added with calls to AddDocTemplate. MFC assumes that the first Icon resource in the application is the application icon, the next Icon resource is the first document icon, and so on.

For example, suppose a document template is the third of three for the application: If there is an Icon resource in the application at index 3, that icon is used for the document template. If not, the icon at index 0 is used as a default.

What do you want to know more about?

  • Document template creation

  • Document/view creation

  • Relationships among MFC objects

  • Creating new documents, windows, and views


Document Template Creation

Home | Overview | How Do I | Sample | Tutorial

While creating a new document in response to a New or Open command from the File menu, the document template also creates a new frame window through which to view the document.

The document-template constructor specifies what types of documents, windows, and views the template will be able to create. This is determined by the arguments you pass to the document-template constructor. The following code illustrates creation of a CMultiDocTemplate for a sample application:

AddDocTemplate( new CMultiDocTemplate( IDR_SCRIBTYPE,
          RUNTIME_CLASS( CScribDoc ),
          RUNTIME_CLASS( CMDIChildWnd ),
          RUNTIME_CLASS( CScribView ) ) );

The pointer to a new CMultiDocTemplate object is used as an argument to AddDocTemplate. Arguments to the CMultiDocTemplate constructor include the resource ID associated with the document type's menus and accelerators, and three uses of the RUNTIME_CLASS macro. RUNTIME_CLASS returns the CRuntimeClass object for the C++ class named as its argument. The three CRuntimeClass objects passed to the document-template constructor supply the information needed to create new objects of the specified classes during the document creation process. The example shows creation of a document template that creates CScribDoc objects with CScribView objects attached. The views are framed by standard MDI child frame windows.

What do you want to know more about?

  • Document/view creation

  • Relationships among MFC objects

  • Creating new documents, windows, and views


Document/View Creation

Home | Overview | How Do I | Sample | Tutorial

The framework supplies implementations of the New and Open commands (among others) on the File menu. Creation of a new document and its associated view and frame window is a cooperative effort among the application object, a document template, the newly created document, and the newly created frame window. The table Object Creators below summarizes which objects create what.

Object Creators

Creator | Creates
Application object | Document template
Document template | Document
Document template | Frame window
Frame window | View

What do you want to know more about?

  • Document template creation

  • Relationships among MFC objects

  • Creating new documents, windows, and views


Relationships Among MFC Objects

Home | Overview | How Do I | Sample | Tutorial

To help put the document/view creation process in perspective, first consider a running program: a document, the frame window used to contain the view, and the view associated with the document.

  • A document keeps a list of the views of that document and a pointer to the document template that created the document.

  • A view keeps a pointer to its document and is a child of its parent frame window.

  • A document frame window keeps a pointer to its current active view.

  • A document template keeps a list of its open documents.

  • The application keeps a list of its document templates.

  • Windows keeps track of all open windows so it can send messages to them.

These relationships are established during document/view creation. The table "Gaining Access to Other Objects in Your Application" below shows how objects in a running program can access other objects. Any object can obtain a pointer to the application object by calling the global function AfxGetApp.

Gaining Access to Other Objects in Your Application

From object | How to access other objects
Document | Use GetFirstViewPosition and GetNextView to access the document's view list. Call GetDocTemplate to get the document template.
View | Call GetDocument to get the document. Call GetParentFrame to get the frame window.
Document frame window | Call GetActiveView to get the current view. Call GetActiveDocument to get the document attached to the current view.
MDI frame window | Call MDIGetActive to get the currently active CMDIChildWnd.

Typically, a frame window has one view, but sometimes, as in splitter windows, the same frame window contains multiple views. The frame window keeps a pointer to the currently active view; the pointer is updated any time another view is activated.

Note A pointer to the main frame window is stored in the m_pMainWnd member variable of the application object. A call to OnFileNew in your override of the InitInstance member function of CWinApp sets m_pMainWnd for you. If you don't call OnFileNew, you must set the variable's value in InitInstance yourself. (SDI COM component (server) applications may not set the variable if /Embedding is on the command line.) Note that m_pMainWnd is now a member of class CWinThread rather than CWinApp.

What do you want to know more about?

  • Document template creation

  • Document/view creation

  • Creating new documents, windows, and views


Creating New Documents, Windows, and Views

Home | Overview | How Do I | Sample | Tutorial

The following figures give an overview of the creation process for documents, views, and frame windows. Other articles that focus on the participating objects provide further details.

Upon completion of this process, the cooperating objects exist and store pointers to each other. The following figures show the sequence in which objects are created. You can follow the sequence from figure to figure.

Sequence in Creating a Document

Sequence in Creating a Frame Window

Sequence in Creating a View

For information about how the framework initializes the new document, view, and frame-window objects, see classes CDocument, CView, CFrameWnd, CMDIFrameWnd, and CMDIChildWnd in the Class Library Reference. Also see Technical Note 22, which explains the creation and initialization processes further under its discussion of the framework's standard commands for the New and Open items on the File menu.

Initializing Your Own Additions to These Classes

The preceding figures also suggest the points at which you can override member functions to initialize your application's objects. An override of OnInitialUpdate in your view class is the best place to initialize the view. The OnInitialUpdate call occurs immediately after the frame window is created and the view within the frame window is attached to its document. For example, if your view is a scroll view (derived from CScrollView rather than CView), you should set the view size based on the document size in your OnInitialUpdate override. (This process is described in the description of class CScrollView.) You can override the CDocument member functions OnNewDocument and OnOpenDocument to provide application-specific initialization of the document. Typically, you must override both since a document can be created in two ways.

In most cases, your override should call the base class version. For more information, see the named member functions of classes CDocument, CView, CFrameWnd, and CWinApp in the Class Library Reference.

What do you want to know more about?

  • Document template creation

  • Document/view creation

  • Relationships among MFC objects


Managing the State Data of MFC Modules

Home | Overview | How Do I | Sample | Tutorial

This article discusses the state data of MFC modules and how this state is updated when the flow of execution (the path code takes through an application when executing) enters and leaves a module. Switching module states with the AFX_MANAGE_STATE and METHOD_PROLOGUE macros is also discussed.

Note The term "module" here refers to an executable program, or to a DLL (or set of DLLs) that operate independently of the rest of the application, but uses a shared copy of the MFC DLL. An ActiveX control is a typical example of a module.

As shown in the figure "State Data of a Single Module (Application)," MFC has state data for each module used in an application. Examples of this data include: Windows instance handles (used for loading resources), pointers to the current CWinApp and CWinThread objects of an application, OLE module reference counts, and a variety of maps that maintain the connections between Windows object handles and corresponding instances of MFC objects. However, when an application uses multiple modules, the state data of each module is not application-wide. Rather, each module has its own private copy of the MFC's state data.

State Data of a Single Module (Application)

A module's state data is contained in a structure and is always available via a pointer to that structure. When the flow of execution enters a particular module, as shown in the figure "State Data of Multiple Modules," that module's state must be the "current" or "effective" state. Therefore, each thread object has a pointer to the effective state structure of that application. Keeping this pointer updated at all times is vital to managing the application's global state and maintaining the integrity of each module's state. Incorrect management of the global state can lead to unpredictable application behavior.

State Data of Multiple Modules

In other words, each module is responsible for correctly switching between module states at all of its entry points. An "entry point" is any place where the flow of execution can enter the module's code. Entry points include:

  • Exported functions in a DLL

  • Member functions of COM interfaces

  • Window procedures


Exported DLL Function Entry Points

Home | Overview | How Do I | Sample | Tutorial

For exported functions of a DLL, use the AFX_MANAGE_STATE macro to maintain the proper global state when switching from the DLL module to the calling application's DLL.

When called, this macro sets pModuleState, a pointer to an AFX_MODULE_STATE structure containing global data for the module, as the effective module state for the remainder of the containing scope of the function. Upon leaving the scope containing the macro, the previous effective module state is automatically restored.

This switching is achieved by constructing an instance of an AFX_MODULE_STATE class on the stack. In its constructor, this class obtains a pointer to the current module state and stores it in a member variable, and then sets pModuleState as the new effective module state. In its destructor, this class restores the pointer stored in its member variable as the effective module state.

If you have an exported function, such as one that launches a dialog box in your DLL, you need to add the following code to the beginning of the function:

AFX_MANAGE_STATE(AfxGetStaticModuleState( ))

This swaps the current module state with the state returned from AfxGetStaticModuleState until the end of the current scope.

Problems with resources in DLLs will occur if the AFX_MANAGE_STATE macro is not used. By default, MFC uses the resource handle of the main application to load the resource template. This template is actually stored in the DLL. The root cause is that MFC's module state information has not been switched by the AFX_MANAGE_STATE macro. The resource handle is recovered from MFC's module state. Not switching the module state causes the wrong resource handle to be used.

AFX_MANAGE_STATE does not need to be put into every function in the DLL. For example, InitInstance can be called by the MFC code in the application without AFX_MANAGE_STATE because MFC automatically shifts the module state before InitInstance and then switches it back after InitInstance returns. The same is true for all message-map handlers. Regular DLLs actually have a special master window procedure that automatically switches the module state before routing any message.


COM Interface Entry Points

Home | Overview | How Do I | Sample | Tutorial

For member functions of a COM interface, use the METHOD_PROLOGUE macro to maintain the proper global state when calling methods of an exported interface.

Typically, member functions of interfaces implemented by CCmdTarget-derived objects already use this macro to provide automatic initialization of the pThis pointer. For example:

// Inner IUnknown implementation (for aggregation)

STDMETHODIMP_(ULONG) CInnerUnknown::AddRef()
{
   METHOD_PROLOGUE_(CCmdTarget, InnerUnknown)
   return pThis->InternalAddRef();
}

For additional information, see Technical Note 38, "MFC/OLE IUnknown Implementation."

The METHOD_PROLOGUE macro is defined as:

#define METHOD_PROLOGUE(theClass, localClass) \
   theClass* pThis = \
      ((theClass*)((BYTE*)this - offsetof(theClass, m_x##localClass))); \
   AFX_MANAGE_STATE(pThis->m_pModuleState) \

The portion of the macro concerned with managing the global state is:

AFX_MANAGE_STATE( pThis->m_pModuleState )

In this expression, m_pModuleState is assumed to be a member variable of the containing object. It is implemented by the CCmdTarget base class, and is initialized to the appropriate value by COleObjectFactory, when the object is instantiated.


Window Procedure Entry Points

Home | Overview | How Do I | Sample | Tutorial

To protect MFC window procedures, a module static links with a special window procedure implementation. The linkage occurs automatically when the module is linked with MFC. This window procedure uses the AFX_MANAGE_STATE macro to properly set the effective module state, then it calls AfxWndProc, which in turn delegates to the WindowProc member function of the appropriate CWnd-derived object.


Idle Loop Processing

Home | Overview | How Do I | Sample | Tutorial

Many applications perform lengthy processing "in the background." Sometimes performance considerations dictate using multithreading for such work. Threads involve extra development overhead, so they are not recommended for simple tasks like the idle-time work that MFC does in the OnIdle function. This article focuses on idle processing. For more information about multithreading, see the article Multithreading Topics.

Some kinds of background processing are appropriately done during intervals that the user is not otherwise interacting with the application. In an application developed for the Microsoft Windows operating system, an application can perform idle-time processing by splitting a lengthy process into many small fragments. After processing each fragment, the application yields execution control to Windows using a PeekMessage loop.

This article explains two ways to do idle processing in your application:

  • Using PeekMessage in MFC's main message loop

  • Embedding another PeekMessage loop somewhere else in the application

PeekMessage in the MFC Message Loop

In an application developed with MFC, the main message loop in the CWinThread class contains a message loop that calls the PeekMessage Win32 API. This loop also calls the OnIdle member function of CWinThread between messages. An application can process messages in this idle time by overriding the OnIdle function.

Note Run, OnIdle, and certain other member functions are now members of class CWinThread rather than of class CWinApp. CWinApp is derived from CWinThread.

For more information about performing idle processing, see OnIdle in the Class Library Reference.

PeekMessage Elsewhere in Your Application

Another method for performing idle processing in an application involves embedding a message loop in one of your functions. This message loop is very similar to MFC's main message loop, found in CWinThread::Run. That means such a loop in an application developed with MFC must perform many of the same functions as the main message loop. The following code fragment demonstrates writing a message loop that is compatible with MFC:

while ( bDoingBackgroundProcessing )
{
    MSG msg;
    while ( ::PeekMessage( &msg, NULL, 0, 0, PM_NOREMOVE ) )
    {
        if ( !PumpMessage( ) )
        {
            bDoingBackgroundProcessing = FALSE;
            ::PostQuitMessage( );
            break;
        }
    }
    // let MFC do its idle processing
    LONG lIdle = 0;
    while ( AfxGetApp()->OnIdle(lIdle++ ) )
        ;
    // Perform some background processing here
    // using another call to OnIdle
}

This code, embedded in a function, loops as long as there is idle processing to do. Within that loop, a nested loop repeatedly calls PeekMessage. As long as that call returns a nonzero value, the loop calls CWinThread::PumpMessage to perform normal message translation and dispatching. Although PumpMessage is undocumented, you can examine its source code in the ThrdCore.Cpp file in MFC\Src relative to your Visual C++ installation.

Once the inner loop ends, the outer loop performs idle processing with one or more calls to OnIdle. The first call is for MFC's purposes. You can make additional calls to OnIdle to do your own background work.

For more information about performing idle processing, see OnIdle in the Class Library Reference.


Mixed-Language Programming Topics

Home | Overview | How Do I

Mixed-language programming is the process of writing a program using modules from different languages, such as C and Fortran. Visual C++ lets you do mixed-language programming with C, C++, Fortran, and MASM.

What do you want to know more about?

  • Mixed-language programming issues

  • C calls to Fortran

  • Fortran calls to C

  • Building my mixed-language program

  • Using C++ in mixed-language programs

  • Handling data types in multiple languages


Mixed-Language Issues

Home | Overview | How Do I

This section reviews basic concepts of mixed-language programming, and introduces relevant new Win32 features. For example, the __stdcall keyword replaces the fortran and pascal keywords in C modules. Another important aspect of Win32 is that all addresses are the same size, simplifying pass by reference. Thus, you may want to review this section even if you have written mixed-language programs extensively for MS-DOS.

Mixed-language programming is possible with Microsoft languages because each language implements functions, subroutines, and procedures approximately the same way. The following table shows how different kinds of routines from each language equate to each other. For example, a C main program could call an external void function, which is actually implemented as a Fortran subroutine.

Language Equivalents for Calls to Routines

Language | Call with return value | Call with no return value
Assembly language | Procedure | Procedure
C and C++ | function | (void) function
Fortran | FUNCTION | SUBROUTINE

In this family of articles, the term “routine” refers to functions, subroutines, and procedures from different languages. This definition does not include macros or inline functions, which are not implemented using the stack.

There are some important differences in the way languages implement these routines, however. This article family presents a series of keywords, attributes, and techniques to reconcile these differences, which fall into three categories:

  • Adjusting calling conventions

  • Adjusting naming conventions

  • Passing by value or by reference

In addition, you need to reconcile differences in the way individual data types (strings, arrays, common blocks, and so on) may be treated. This important and complex topic is discussed in Handling Data Types in Multiple Languages.


Adjusting Calling Conventions

Home | Overview | How Do I

The calling convention determines how a program makes a call and where the parameters are passed. In a single-language program, calling conventions are nearly always correct, because there is one default for all modules and because header files enforce consistency between the caller and the called routine. In a mixed-language program, different languages cannot share the same header files. It’s easy to link Fortran and C modules that use different calling conventions, and the error isn’t apparent until the bad call is made at run time, causing immediate program failure. Therefore, you should check calling conventions carefully for each mixed-language call.

The following table summarizes how C and Fortran calling conventions work.

C and Fortran Calling Conventions

Calling convention | Parameter passing | Stack cleared by
C/C++ | Pushes parameters on the stack, in reverse order (right to left) | Caller
Fortran (__stdcall) | Pushes parameters on the stack, in reverse order (right to left) | Called function

In C and C++ modules, you can specify the Fortran calling convention by using the __stdcall keyword in a function prototype or definition. The __stdcall convention is also used by window procedures and API functions. For example, the following C language prototype sets up a function call to a subroutine using the Fortran calling convention:

extern void __stdcall fortran_routine (int n);

Instead of changing the calling convention of the C code, you can adjust the Fortran source code by using the C attribute, enclosed in brackets ([ ]). For example, the following declaration assumes the subroutine is called with the C calling convention:

      SUBROUTINE CALLED_FROM_C [C] (A)
      INTEGER*4 A

It should be clear that calling conventions need only agree between individual calls and the called routines, and that the conventions must be the same: Both caller and called routine must use the C/C++ convention or both must use the __stdcall convention (the Fortran default).

Note In programs written for the graphical user interface of Windows, PASCAL, WINAPI, and CALLBACK are all defined with __stdcall. But the C language default is still cdecl.

The following table summarizes how to specify calling conventions. You can always specify calling conventions explicitly rather than relying on the default, which is a good technique for mixed-language programming.

Specifying Calling Conventions

Language | C calling convention | Fortran calling convention
C/C++ | cdecl (default) | __stdcall
Fortran | C attribute | STDCALL attribute (default)


Adjusting Naming Conventions

Home | Overview | How Do I

The naming convention determines how a language alters a symbol name as it places the name in an .OBJ file. This is an issue for external data symbols shared between modules as well as for external routines. Parameter names are never affected. The reasons for altering the name include case sensitivity or lack thereof, type decoration, and other issues. Note that you can always see exactly how a name has been placed in an .OBJ file by using the DUMPBIN utility with the /SYMBOLS option. If naming conventions are not reconciled, the program cannot successfully link. You will receive an “unresolved external” error.

Naming conventions are closely related to calling conventions because the keywords that specify calling conventions affect naming conventions as well. However, C/C++ preserves case sensitivity in its symbol tables and Fortran does not, which can necessitate some additional work on your part. Fortunately, you can use the Fortran ALIAS attribute to resolve any discrepancy in names.

The following table summarizes how C, Fortran, and C++ handle public names.

Naming Conventions in C, Fortran, and C++

Language | Name translated as | Case of name in OBJ file
C, cdecl (default) | _name | Mixed case preserved
C, __stdcall | _name@nn | Mixed case preserved
Fortran [C] | _name | All lowercase
Fortran [STDCALL] | _name@nn | All lowercase
Fortran default | _name@nn | All uppercase
C++ | _name@@decoration | Mixed case preserved

In the previous table, nn represents the stack space, in decimal notation, occupied by parameters. For example, assume a function is declared in C as

extern int __stdcall Sum_Up( int a, int b, int c );

Each integer occupies 4 bytes, so the symbol name placed in the .OBJ file is:

_Sum_Up@12

Case sensitivity can present a problem. The 32-bit linker always distinguishes case. The strategy you use to handle a discrepancy due to case depends on whether the situation involves:

  • Calls from C to Fortran, where Fortran cannot be recompiled

  • Symbol names that are all lowercase

  • Mixed-case names

C Calls Using Fortran Names

If you call a Fortran routine from C and cannot recompile the Fortran code, and if the routine uses Fortran defaults, you must use an all-uppercase name to make the call. Use of the __stdcall convention is not enough, because __stdcall (unlike the fortran keyword in 16-bit code) always preserves case. Fortran generates all-uppercase names by default and the C code must match it.

For example, this prototype sets up a call to a Fortran function ffarctan:

extern float __stdcall FFARCTAN( float angle );

All-Lowercase Names

If the name of the routine appears as all lowercase in C, naming conventions are automatically correct when the C or STDCALL attribute is applied to the Fortran declaration. Any case may be used in the Fortran source code, including mixed case; the C and STDCALL attributes change the name to all lowercase. Note that this is a way in which STDCALL differs from the Fortran default behavior.

Mixed-Case Names

If the name of the routine appears as mixed-case in C, and you cannot change the name, you can resolve naming conflicts only by using the Fortran ALIAS attribute. ALIAS is required in this situation so that Fortran will generate mixed-case names.

To use the ALIAS attribute, place the name in quotation marks exactly as it is to appear in the .OBJ file. For example, suppose you are calling a C function that has the following prototype:

extern void My_Proc (int i);

The Fortran call to this function should be declared with the following INTERFACE block:

      INTERFACE TO SUBROUTINE My_Proc [C, ALIAS:’_My_Proc’] (I)
      INTEGER*4 I
      END

Note When using the __stdcall convention, both Fortran and C should calculate parameter-space size by rounding each parameter upward to multiples of four (because it is more efficient to keep the stack-pointer aligned on 4-byte boundaries). Thus, the function Print_Nums, which is passed a byte, a short, and a long integer should be translated as _Print_Nums@12. However, there is an early version of 32-bit Fortran that translates this as _Print_Nums@7, not rounding upward. To correct the discrepancy, use the ALIAS attribute.


Passing By Value or By Reference

Home | Overview | How Do I

Each individual parameter can be passed by value or by reference (which places the address of the parameter on the stack). In Fortran, C, and C++, all addresses are the same size (4 bytes), so there is no passing by near or far reference. You need to make sure that for every call, the calling program and the called routine agree on how each parameter is passed. Otherwise, the called routine receives bad data.

The C/C++ technique for passing parameters is always the same, regardless of calling convention: All parameters are passed by value, except for arrays, which are translated into the address of the first member. To pass data by reference, pass a pointer to it.

The Fortran technique for passing parameters changes depending on the calling convention specified. By default, Fortran passes all data by reference (except the hidden length argument of strings, which is a special case). If the C or STDCALL attribute is used, the default changes to passing all data by value.

In Fortran, use the VALUE and REFERENCE attributes to specify pass by value or pass by reference. In mixed-language programming, it is a good idea to always specify passing technique explicitly rather than relying on defaults. For example, the following C declaration sets up a call to a Fortran subroutine:

extern void __stdcall TESTPROC( int ValParm, int *RefParm );

In the following example, the definition of TESTPROC in Fortran declares how each parameter is passed. The REFERENCE attribute is not strictly necessary in this example, but using it is a good idea, in case you later change the calling convention.

      SUBROUTINE TESTPROC( VALPARM, REFPARM )
      INTEGER*4 VALPARM [VALUE]
      INTEGER*4 REFPARM [REFERENCE]
      END

The following table summarizes parameter-passing defaults. Note that an array name in C is equated to its starting address. Therefore, arrays are passed by reference. To pass an array by value, declare a structure with the array as its only member.

C/C++ and Fortran Defaults for Passing Parameters

Language | By value | By reference
C/C++ | variable | * variable
Fortran | variable [VALUE] | variable [REFERENCE], or variable
Fortran [C or STDCALL] | variable [VALUE], or variable | variable [REFERENCE]
C/C++ arrays | struct { type } variable | variable


C Calls to Fortran

Home | Overview | How Do I

This article applies the principles in Mixed-Language Issues to a typical case involving one function call and one subroutine call from C to Fortran. Default conventions are assumed for Fortran, so adjustments are made to the C code.

The C main program uses the __stdcall keyword to call the Fortran routines with the correct calling convention. The C source must use all-uppercase names for the routines, because this Fortran code does not use the C, STDCALL, or ALIAS attributes. Finally, pass by value and pass by reference are specified explicitly, though pass by reference would have been assumed by default for Fortran.

/*     File CMAIN.C   */

#include <stdio.h>

extern int __stdcall FACT (int n);
extern void __stdcall PYTHAGORAS (float a, float b, float *c);

main()
{
    float c;
    printf("Factorial of 7 is: %d\n", FACT(7));
    PYTHAGORAS (30, 40, &c);
    printf("Hypotenuse if sides 30, 40 is: %f\n", c);
}

C    File FORSUBS.FOR
C
      INTEGER*4 FUNCTION Fact (n)
      INTEGER*4 n [VALUE]
      INTEGER*4 i, amt
      amt = 1
      DO i = 1, n
        amt = amt * i
      END DO
      Fact = amt
      END

      SUBROUTINE Pythagoras (a, b, c)
      REAL*4 a [VALUE]
      REAL*4 b [VALUE]
      REAL*4 c [REFERENCE]
      c = SQRT (a * a + b * b)
      END


Fortran Calls to C

Home | Overview | How Do I

This article applies the principles in Mixed-Language Issues to a typical case involving one function call and one subroutine call from Fortran to C. Default conventions are assumed for C, so adjustments are made to the Fortran code. The example in this article is the converse of that in C Calls to Fortran.

The Fortran main program uses the C attribute to call the C functions with the correct calling convention. The C attribute causes Fortran to generate all-lowercase names, so the ALIAS attribute must be used to preserve mixed case. Finally, pass by value and pass by reference are specified explicitly, though pass by value would have been assumed because of the C attribute.

C   File FORMAIN.FOR
C
      INTERFACE TO INTEGER*4 FUNCTION Fact [C,ALIAS:'_Fact'] (n)
      INTEGER*4 n [VALUE]
      END

      INTERFACE TO SUBROUTINE Pythagoras [C,ALIAS:'_Pythagoras'] (a,b,c)
      REAL*4 a [VALUE]
      REAL*4 b [VALUE]
      REAL*4 c [REFERENCE]
      END

      INTEGER*4 Fact
      REAL*4 c
      WRITE (*,*) 'Factorial of 7 is ', Fact (7)
      CALL Pythagoras (30, 40, c)
      WRITE (*,*) 'Hypotenuse if sides 30, 40 is ', c
      END

/*  File CSUBS.C  */

#include <math.h>

int Fact( int n )
{
    if (n > 1)
        return( n * Fact( n - 1 ));
    return 1;
}

void Pythagoras( float a, float b, float *c)
{
    *c = sqrt( a * a + b * b );
}


Building the Mixed-Language Program

Home | Overview | How Do I

In Win32, the choice of libraries is much simpler than it is in 16-bit environments. Consequently, it is easier to build a mixed-language program. To link C and Fortran modules, use the Fortran linker; the linker should find the correct default libraries.

For example, the simple console applications featured in other articles in this family require no special options. The CMAIN application can be created with the following commands:

cl /c cmain.c
fl32 cmain.obj forsubs.for

The FORMAIN application can be created with the following commands:

cl /c csubs.c
fl32 formain.for cmain.obj

Multithread applications should have full multithread support, so if you use LIBFMT.LIB, make sure that LIBCMT.LIB is specified as a default library as well.


Mixed-Language Programming with C++

Home | Overview | How Do I

C++ uses the same calling convention and parameter-passing techniques as C, but naming conventions are different because of C++ decoration of external symbols. By causing C++ to drop name decoration, the extern "C" syntax makes it possible for a C++ module to share data and routines with other languages.

The following example declares prn as an external function using the C naming convention. This declaration appears in C++ source code.

extern "C"
{
    void prn();
}

To call functions written in Fortran (or MASM), declare the function as you would in C and use a "C" linkage specification. For example, to call the Fortran function FACT from C++, declare it as follows:

extern "C" { int __stdcall FACT( int n ); }

The extern "C" syntax can be used to adjust a call from C++ to other languages, or to change the naming convention of C++ routines called from other languages. However, extern "C" can be used only from within C++. If the C++ code does not use extern "C" and cannot be changed, you can call C++ routines only by determining the name decoration and generating it from the other language. You can always determine the decoration by using the DUMPBIN utility. Use this approach only as a last resort, because the decoration scheme is not guaranteed to remain the same between versions.

Use of extern "C" has some restrictions:

  • You cannot declare a member function with extern "C".

  • You can specify extern "C" for only one instance of an overloaded function; all other instances of an overloaded function have C++ linkage.

For more information on the extern "C" linkage specification, see Linkage Specifications in C++ Language Reference.


Handling Data Types in Multiple Languages

Home | Overview | How Do I

Even when you’ve reconciled calling conventions, naming conventions, and parameter passing technique (pass by value or pass by reference), it is still possible to pass data incorrectly, because each language has different ways of handling data types. The following sections describe how to pass each type of data between languages.

  • Numeric Data Types

  • Pointers (Address Variables)

  • Declaring and Indexing Arrays

  • Character Strings

  • Structures, COMPLEX, and LOGICAL Types

  • Common Blocks


Numeric Data Types

Normally, passing numeric data does not present a problem. The most important thing to keep in mind when passing numeric types is that in Win32, the C int type is 4 bytes, not 2 bytes, and therefore is equivalent to the Fortran INTEGER*4 type. The COMPLEX type is a special case and is discussed in a later section. The following table summarizes equivalent numeric data types for Fortran, MASM, and C/C++.

Equivalent Fortran, MASM, and C/C++ Numeric Data Types

Fortran | MASM | C/C++
CHARACTER*1 | BYTE | unsigned char
INTEGER*1 | SBYTE | char
(none) | WORD | unsigned short
INTEGER*2 | SWORD | short
(none) | DWORD | unsigned long, unsigned int
INTEGER, INTEGER*4 | SDWORD | long, int
REAL, REAL*4 | REAL4 | float
DOUBLE PRECISION, REAL*8 | REAL8 | double

If a C program passes an unsigned data type to a Fortran routine, the routine can accept the argument as the equivalent signed data type, but you should be careful that the range of the signed type is not exceeded.


Pointers (Address Variables)

In Fortran, you use the LOC function to extract the address of a variable. (In Win32, all addresses are 4 bytes, so there is no separate LOCFAR function, as there is for 16-bit environments.) Because Fortran does not have a pointer type, the result of the LOC function must be stored in an INTEGER*4 variable or passed as a parameter of type INTEGER*4. Generally, a pointer should be passed by value.

Passing a pointer by value is equivalent to passing what it points to by reference. In the following example, the two subroutine calls push identical data on the stack, and in each case the C routine called should expect an address. The two functions require different parameter declarations.

      INTERFACE TO SUBROUTINE pass_addr1 [C] (addr_data)
      REAL*8 addr_data [REFERENCE]
      END

      INTERFACE TO SUBROUTINE pass_addr2 [C] (addr_data)
      INTEGER*4 addr_data [VALUE]
      END

      REAL*8 x
      INTEGER*4 ptr
      CALL pass_addr1 (x)
      ptr = LOC(x)
      CALL pass_addr2 (ptr)


Declaring and Indexing Arrays

Each language varies in the way that arrays are declared and indexed. Array indexing is a source-level consideration and involves no difference in the underlying data. There are two differences in the way elements are indexed by each language:

  • The value of the lower array bound is different.

    By default, Fortran indexes the first element of an array as 1. C and C++ index it as 0. Fortran subscripts should therefore be 1 higher. (Fortran also provides the option of specifying another integer lower bound.)

  • C varies subscripts in row-major order, Fortran in column-major order.

The differences in how subscripts are varied only affect arrays with more than one dimension. With row-major order (C and C++), the rightmost dimension changes fastest. With column-major order (Fortran), the leftmost dimension changes fastest. Thus, in C, the first four elements of an array declared as X[3][3] are

X[0][0]    X[0][1]    X[0][2]    X[1][0]

In Fortran, the four elements are

X(1,1)     X(2,1)     X(3,1)     X(1,2)

The preceding C and Fortran arrays illustrate the difference between row-major and column-major order, and also the difference in the assumed lower bound between C and Fortran. The following table shows equivalencies for array declarations in each language. In this table, r is the number of elements of the row dimension (which changes the slowest), and c is the number of elements of the column dimension (which changes the fastest).

Equivalent Array Declarations

Language | Array declaration | Array reference
C/C++ | type x[r][c], or struct { type x[r][c]; } x 1 | x[r][c]
Fortran | type x(c, r) | x(c+1, r+1)

1. Use a structure to pass an array by value in C and C++.

The order of indexing extends to any number of dimensions you declare. For example, the C declaration

int arr1[2][10][15][20];

is equivalent to the Fortran declaration

INTEGER*2 ARR1( 20, 15, 10, 2 )

The constants used in a C array declaration represent dimensions, not upper bounds as they do in other languages. Therefore, the last element in the C array declared as int arr[5][5] is arr[4][4], not arr[5][5].

The following code provides a complete example, showing how arrays are passed as arguments to a routine.

C    File FORARRS.FOR
C

      INTERFACE TO SUBROUTINE Pass_Arr [C,ALIAS:'_Pass_Arr'] ( Array )
      INTEGER*4 Array( 10, 10 )
      END

      INTEGER*4 Arr( 10, 10 )
      CALL Pass_Arr( Arr )
      write (*,*) 'Array values: ', Arr(1, 10), Arr(2, 10)
      END

/*     File CF.C  */

#include <stdio.h>

void Pass_Arr ( int arr[10][10] )
{
    arr[9][0] = 10;
    arr[9][1] = 20;
}


Character Strings

In Win32, Fortran by default passes a hidden length argument for strings. This argument is easily accessible to other languages, unlike the string-length information passed in 16-bit versions of Fortran. The hidden length argument consists of an unsigned 4-byte integer, always passed by value, immediately following the character string argument.

For example, if a Fortran program sets up the following call to a routine, Pass_Str, implemented in C:

      INTERFACE TO SUBROUTINE Pass_Str (string)
      CHARACTER*(*) string
      END

Then the C routine must expect two arguments:

void __stdcall PASS_STR (char *string, unsigned int length_arg )

Another important difference is in the format of the strings themselves. C strings are null-terminated. For example, given the following assignment:

Char *cstring="C text string";

The string data is stored as shown in the following figure.

Fortran strings are not null-terminated, and they are padded with blank spaces when assigned string data that is shorter than the declared length. For example, given the following assignment:

      CHARACTER*14 forstring
      DATA FORSTRING /"Fortran STRING'/

The string data is stored as follows. Note that if the string were any longer, it would be padded with trailing blanks.

A more efficient approach, wherever possible, is to adopt C string behavior. When the C or STDCALL attribute is applied to a routine, Fortran does not pass a hidden length argument. Furthermore, you can use the C-string feature to assign null-terminated string data in Fortran, as follows:

      CHARACTER*20 forstring
      DATA forstring /'This is a string'C/

The string variable, forstring, can then be passed to a C routine. If the C or STDCALL attribute is used, Fortran passes forstring just as C does: pushing the address of a null-terminated string onto the stack, with no hidden length argument.

Note Fortran functions of type CHARACTER*(*) place a hidden string argument at the beginning of the parameter list; this may include both string address and length, as appropriate. C functions that implement such a call from Fortran must declare this hidden string argument explicitly and use it to return a value. However, you are more likely to avoid errors by not using character-string return types. Use subroutines whenever possible.

The following example demonstrates how a Fortran main program calls a C function that translates a string to all-uppercase. Because the string is passed by reference, there is no need to use a string return type. Note that the C attribute stops Fortran from passing a hidden string-length argument, and the DATA statement uses a “C” to specify null termination.

C    File FORMAIN.FOR
C
      INTERFACE TO SUBROUTINE Ucase [C,ALIAS:'_Ucase'] (text)
      CHARACTER*(*) text [REFERENCE]
      END

      CHARACTER*40 forstring
      DATA forstring /'This is a sample string.'C/
      WRITE (*, *) forstring
      CALL Ucase (forstring)
      WRITE (*, *) forstring
      END

/*     File CSTR.C   */

#include <ctype.h>

void Ucase( char *string )
{
    char *ptr;

    for (ptr = string; *ptr; ptr++)
        *ptr = toupper( *ptr );
}

This use of C strings is usually the best approach, because most C library functions, as well as API functions, assume null-termination. However, if you use C to write string-manipulation functions, it is a good idea to translate null-terminated strings back into blank-padded strings after the C function returns. The following code performs this operation:

      SUBROUTINE Fix_C_Str (text, length)
      CHARACTER*(*) text
      INTEGER*4 length

      INTEGER*4 i

C  Find the first null ('\0')

      i = 1
      DO WHILE ((i .LE. length) .AND. (text(i:i) .NE. '\0'))
        i = i + 1
      END DO

C  Pad with blanks to the end of the string

      DO WHILE (i .LE. length)
        text (i:i) = ' '
      END DO
      END


Structures, COMPLEX, and LOGICAL Types

The Fortran structure variable, defined with the STRUCTURE keyword and declared with the RECORD statement, is equivalent to C struct declarations. You can pass structures by value or by reference. Be careful, however, about the effect of structure alignment if you are going to share structures.

C, C++, and MASM do not directly implement the Fortran types COMPLEX*8 and COMPLEX*16. However, you can write structures that are equivalent. The type COMPLEX*8 has two fields, both of which are 4-byte floating-point numbers; the first contains the real-number component, and the second contains the imaginary-number component. The type COMPLEX is equivalent to the type COMPLEX*8. The type COMPLEX*16 is similar to COMPLEX*8. The only difference is that each field of COMPLEX*16 contains an 8-byte floating-point number.

Note Fortran functions of type COMPLEX place a hidden COMPLEX argument at the beginning of the parameter list. C functions that implement such a call from Fortran must declare this argument explicitly, and use it to return a value. The C return type should be void.

Here are the C/C++ structure definitions for the Fortran COMPLEX types.

struct complex8 {
    float   real, imag;
};

struct complex16 {
    double  real, imag;
};

A Fortran LOGICAL*2 is stored as a 1-byte indicator value (1=true, 0=false) followed by one unused byte. A Fortran LOGICAL*4 is stored as a 1-byte indicator value followed by three unused bytes. The type LOGICAL is equivalent to LOGICAL*4.

To pass or receive a Fortran LOGICAL type, use an integer. Note that only the low byte is tested or used by Fortran.

The C++ class type has the same layout as the corresponding C struct type, unless the class defines virtual functions or has base classes. Classes that lack those features can be passed in the same way as C structures.


Common Blocks

You can pass individual members of a Fortran common block in an argument list, just as you can any data item. However, you can also give a different language module access to the entire common block.

C or C++ modules can reference the items of a common block by first declaring a structure with fields that correspond to the common-block variables. Having defined a structure with the appropriate fields, the C or C++ module must then connect with the common block. The next two sections present methods for gaining access to common blocks.


Passing the Address of a Common Block

To pass the address of a common block, simply pass the address of the first variable in the block. (In other words, pass the first variable by reference.) The receiving C or C++ module should expect to receive a structure by reference.

In the following example, the C function initcb receives the address of the variable N, which it considers to be a pointer to a structure with three fields:

C      Fortran SOURCE CODE
C
       COMMON /CBLOCK/N, X, Y
       INTEGER*4 N
       REAL*8    X, Y
.
.
.
       CALL INITCB( N )

/* C source code */

struct block_type
{
    long   n;
    double x;
    double y;
};

initcb( struct block_type * block_hed )
{
    block_hed->n = 1;
    block_hed->x = 10.0;
    block_hed->y = 20.0;
}


Accessing Common Blocks Directly

You can access Fortran common blocks directly by defining a structure with the appropriate fields and then declaring the structure as an external data symbol. For example, the following code defines a structure named CBLOCK, which the C code can use to directly access items in the Fortran common block named CBLOCK:

struct block_type
{
    int    n;
    double x;
    double y;
};

extern struct block_type CBLOCK;


Multithreading Topics

Home | Overview | How Do I | Sample

Visual C++ allows you to have multiple concurrent threads of execution running simultaneously. With multithreading, you can spin off background tasks, manage simultaneous streams of input, manage a user interface, and much more. This family of articles covers two ways to use multiple threads:

  • Using C and the Win32 API

  • Using C++ and MFC

What do you want to know more about?

  • What multithreading is all about

  • Win32 support for multithreading

  • MFC support for multithreading

  • Multithreading issues and problem areas

  • Sample Win32 multithreading code

  • Sample MFC multithreading code

  • Sharing resources among threads

  • Thread local storage

  • Synchronizing threads that use shared resources

  • Threads with a user interface

  • Worker threads for background processing

  • Programming tips for MFC multithreaded programming


Multithreading with C and Win32

Home | Overview | How Do I | Sample

Microsoft Visual C++ provides support for creating multithread applications with 32-bit versions of Microsoft Windows: Windows NT and Windows 95. You should consider using more than one thread if your application needs to manage multiple activities, such as simultaneous keyboard and mouse input. One thread can process keyboard input while a second thread filters mouse activities. A third thread can update the display screen based on data from the mouse and keyboard threads. At the same time, other threads can access disk files or get data from a communications port.

With Visual C++, there are two ways to program with multiple threads: use the Microsoft Foundation Class library (MFC) or the C run-time library and the Win32 API. For information on creating multithread applications with MFC, read the Multithreading with C++ and MFC articles after reading these articles about multithreading in C.

This article family explains the features in Visual C++ that support the creation of multithread programs.

Note Win32s does not support multithreading. Calls to the Win32 APIs and C run-time library functions mentioned in this article family will return an error.

What do you want to know more about?

  • What multithreading is about

  • Library support for multithreading

  • Include files for multithreading

  • C Run-Time library functions for thread control

  • Sample multithread program in C

  • Writing a Multithread Win32 Program

  • Compiling and linking multithread programs

  • Avoiding problem areas with multithread programs

  • Thread local storage (TLS)


Multithread Programs

Home | Overview | How Do I | Sample

A thread is basically a path of execution through a program. It is also the smallest unit of execution that Win32 schedules. A thread consists of a stack, the state of the CPU registers, and an entry in the execution list of the system scheduler. Each thread shares all of the process’s resources.

A process consists of one or more threads and the code, data, and other resources of a program in memory. Typical program resources are open files, semaphores, and dynamically allocated memory. A program executes when the system scheduler gives one of its threads execution control. The scheduler determines which threads should run and when they should run. Threads of lower priority may have to wait while higher priority threads complete their tasks. On multiprocessor machines, the scheduler can move individual threads to different processors to “balance” the CPU load.

Each thread in a process operates independently. Unless you make them visible to each other, the threads execute individually and are unaware of the other threads in a process. Threads sharing common resources, however, must coordinate their work by using semaphores or another method of interprocess communication. See Writing a Multithreaded Win32 Program for more information about synchronizing threads.


Library Support for Multithreading

Home | Overview | How Do I | Sample

If one thread is suspended by the Win32 scheduler while executing the printf function, one of the program’s other threads might start executing. If the second thread also calls printf, data might be corrupted. To avoid this situation, access to static data used by the function must be restricted to one thread at a time.

You do not need to serialize access to stack-based (automatic) variables because each thread has a different stack. Therefore, a function that uses only automatic (stack) variables is reentrant. The standard C run-time libraries, such as LIBC, have a limited number of reentrant functions. A multithread program needing to use C run-time library functions that are normally not reentrant should be built with the multithread library LIBCMT.LIB.

The Multithread C Libraries: LIBCMT.LIB and MSVCRT.LIB

The support library LIBCMT.LIB is a reentrant library for creating multithread programs. The MSVCRT.LIB library, which calls code in the shared MSVCRT40.DLL, is also reentrant. When your application calls functions in these libraries, the following rules may apply:

  • All library calls must use the C (__cdecl) calling convention; programs compiled using other calling conventions (such as __fastcall or __stdcall) must use the standard include files for the run-time library functions they call.

  • Variables passed to library functions must be passed by value or cast to a pointer.

Programs built with LIBCMT.LIB do not share C run-time library code or data with any dynamic-link libraries they call.

Alternatives to LIBCMT.LIB and MSVCRT.LIB

If you build a multithread program without using LIBCMT.LIB, you must do the following:

  • Use the standard C libraries and limit library calls to the set of reentrant functions.

  • Use the Win32 API thread management functions, such as CreateThread.

  • Provide your own synchronization for functions that are not reentrant by using Win32 services such as semaphores and the EnterCriticalSection and LeaveCriticalSection functions.

Warning The multithread library LIBCMT.LIB includes the _beginthread and _endthread functions. The _beginthread function performs initialization without which many C run-time functions will fail. You must use _beginthread instead of CreateThread in C programs built with LIBCMT.LIB if you intend to call C run-time functions.

The Multithread Libraries Compile Option

To build a multithread application that uses the C run-time libraries, you must tell the compiler to use a special version of the libraries (LIBCMT.LIB). To select these libraries, first open the Project Settings dialog box (Build menu) and click the C/C++ tab. Select Code Generation from the Category drop-down list box. From the Use Run-Time Library drop-down box, select Multithreaded. Click OK to return to editing.

From the command line, the Multithread Library compiler option (/MT) is the best way to build a multithread program with LIBCMT.LIB. This option, which is automatically set when you specify a multithreaded application when creating a new project, embeds the LIBCMT library name in the object file.


Include Files for Multithreading

Home | Overview | How Do I | Sample

The Microsoft Visual C++ include files contain conditional sections for multithread applications using LIBCMT.LIB. To compile your application with the appropriate definitions, you can:

  • Compile with the Multithread Library compiler option described in the previous section.

  • Define the symbolic constant _MT in your source file or on the command line with the /D compiler option.

Standard include files declare C run-time library functions as they are implemented in the libraries. If you use the Full Optimization (/Ox) or fastcall Calling Convention (/Gr) option, the compiler assumes that all functions should be called using the register calling convention. The run-time library functions were compiled using the C calling convention, and the declarations in the standard include files tell the compiler to generate correct external references to these functions.

See Compiling and Linking Multithread Programs for examples of how to use the _MT constant.


C Run-Time Library Functions for Thread Control

Home | Overview | How Do I | Sample

All Win32 programs have at least one thread. Any thread can create additional threads. A thread can complete its work quickly and then terminate, or it can stay active for the life of the program.

The LIBCMT and MSVCRT C run-time libraries provide two functions for thread creation and termination: _beginthread and _endthread.

The _beginthread function creates a new thread and returns a thread identifier if the operation is successful. The thread terminates automatically if it completes execution, or it can terminate itself with a call to _endthread.

! Warning If you are going to call C run-time routines from a program built with LIBCMT.LIB, you must start your threads with the _beginthread function. Do not use the Win32 functions ExitThread and CreateThread. Using SuspendThread can lead to a deadlock when more than one thread is blocked waiting for the suspended thread to complete its access to a C run-time data structure.

The _beginthread Function

The _beginthread function creates a new thread. A thread shares the code and data segments of a process with other threads in the process, but has its own unique register values, stack space, and current instruction address. The system gives CPU time to each thread, so that all threads in a process can execute concurrently.

The _beginthread function is similar to the CreateThread function in the Win32 API but has these differences:

  • The _beginthread function lets you pass multiple arguments to the thread.

  • The _beginthread function initializes certain C run-time library variables. This is important only if you use the C run-time library in your threads.

  • CreateThread provides control over security attributes. You can use this function to start a thread in a suspended state.

The _beginthread function returns a handle to the new thread if successful or –1 if there was an error.

The _endthread Function

The _endthread function terminates a thread created by _beginthread. Threads terminate automatically when they finish. The _endthread function is useful for conditional termination from within a thread. A thread dedicated to communications processing, for example, can quit if it is unable to get control of the communications port.


Sample Multithread C Program

Home | Overview | How Do I | Sample

BOUNCE.C is a sample multithread program that creates a new thread each time the letter a or A is typed. Each thread bounces a “happy face” of a different color around the screen. Up to 32 threads can be created. The program’s normal termination occurs when q or Q is typed. See Compiling and Linking Multithread Programs for details on compiling and linking BOUNCE.C.

/*  Bounce - Creates a new thread each time the letter 'a' is typed.
 *  Each thread bounces a happy face of a different color around the screen.
 *  All threads are terminated when the letter 'Q' is entered.
 *
 *  This program requires the multithread library. For example, compile
 *  with the following command line:
 *      CL /MT BOUNCE.C
 */

#include <windows.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <process.h>

#define MAX_THREADS  32

/* getrandom returns a random number between min and max, which must be in
 * integer range.
 */
#define getrandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

void main( void );                     /* Thread 1: main */
void KbdFunc( void  );                 /* Keyboard input, thread dispatch */
void BounceProc( char * MyID );        /* Threads 2 to n: display */
void ClearScreen( void );              /* Screen clear */
void ShutDown( void );                 /* Program shutdown */
void WriteTitle( int ThreadNum );      /* Display title bar information */

HANDLE  hConsoleOut;                   /* Handle to the console */
HANDLE  hRunMutex;                     /* "Keep Running" mutex */
HANDLE  hScreenMutex;                  /* "Screen update" mutex  */
int     ThreadNr;                      /* Number of threads started */
CONSOLE_SCREEN_BUFFER_INFO csbiInfo;   /* Console information */

void main()                            /* Thread One */
{
    /* Get display screen information & clear the screen.*/
    hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
    GetConsoleScreenBufferInfo( hConsoleOut, &csbiInfo );
    ClearScreen();
    WriteTitle( 0 );
    /* Create the mutexes and reset thread count. */
    hScreenMutex = CreateMutex( NULL, FALSE, NULL );   /* Cleared */
    hRunMutex = CreateMutex( NULL, TRUE, NULL );       /* Set */
    ThreadNr = 0;

    /* Start waiting for keyboard input to dispatch threads or exit. */
    KbdFunc();

    /* All threads done. Clean up handles. */
    CloseHandle( hScreenMutex );
    CloseHandle( hRunMutex );
    CloseHandle( hConsoleOut );
}

void ShutDown( void )                  /* Shut down threads */
{
    while ( ThreadNr > 0 )
    {
            /* Tell thread to die and record its death. */
            ReleaseMutex( hRunMutex );
            ThreadNr--;
    }
    /* Clean up display when done */
    WaitForSingleObject( hScreenMutex, INFINITE );
    ClearScreen();
}

void KbdFunc( void )                   /* Dispatch and count threads. */
{
    int         KeyInfo;

    do
    {
        KeyInfo = _getch();
        if( tolower( KeyInfo ) == 'a' && ThreadNr < MAX_THREADS )
        {
            ThreadNr++;
            _beginthread( BounceProc, 0, &ThreadNr );
            WriteTitle( ThreadNr );
        }
    } while( tolower( KeyInfo ) != 'q' );

    ShutDown();
}

void BounceProc( char *MyID )
{
    char      MyCell, OldCell;
    WORD      MyAttrib, OldAttrib;
    char      BlankCell = 0x20;
    COORD     Coords, Delta;
    COORD     Old = {0,0};
    DWORD     Dummy;

/* Generate update increments and initial display coordinates. */
    srand( (unsigned) *MyID * 3 );
    Coords.X = getrandom( 0, csbiInfo.dwSize.X - 1 );
    Coords.Y = getrandom( 0, csbiInfo.dwSize.Y - 1 );
    Delta.X = getrandom( -3, 3 );
    Delta.Y = getrandom( -3, 3 );

    /* Set up "happy face" & generate color attribute from thread number.*/
    if( *MyID > 16)
        MyCell = 0x01;                 /* outline face */
    else
        MyCell = 0x02;                 /* solid face */
    MyAttrib =  *MyID & 0x0F;          /* force black background */

    do
    {
        /* Wait for display to be available, then lock it. */
        WaitForSingleObject( hScreenMutex, INFINITE );

        /* If we still occupy the old screen position, blank it out. */
        ReadConsoleOutputCharacter( hConsoleOut, &OldCell, 1, Old, &Dummy );
        ReadConsoleOutputAttribute( hConsoleOut, &OldAttrib, 1, Old, &Dummy );
        if (( OldCell == MyCell ) && (OldAttrib == MyAttrib))
            WriteConsoleOutputCharacter( hConsoleOut, &BlankCell, 1, Old, &Dummy );

        /* Draw new face, then clear screen lock */
        WriteConsoleOutputCharacter( hConsoleOut, &MyCell, 1, Coords, &Dummy );
        WriteConsoleOutputAttribute( hConsoleOut, &MyAttrib, 1, Coords, &Dummy );
        ReleaseMutex( hScreenMutex );

        /* Increment the coordinates for next placement of the block. */
        Old.X = Coords.X;
        Old.Y = Coords.Y;
        Coords.X += Delta.X;
        Coords.Y += Delta.Y;

        /* If we are about to go off the screen, reverse direction */
        if( Coords.X < 0 || Coords.X >= csbiInfo.dwSize.X )
        {
            Delta.X = -Delta.X;
            Beep( 400, 50 );
        }
        if( Coords.Y < 0 || Coords.Y > csbiInfo.dwSize.Y )
        {
            Delta.Y = -Delta.Y;
            Beep( 600, 50 );
        }
    }
    /* Repeat while RunMutex is still taken. */
    while ( WaitForSingleObject( hRunMutex, 75L ) == WAIT_TIMEOUT );

}

void WriteTitle( int ThreadNum )
{
    char    NThreadMsg[80];

    sprintf( NThreadMsg, "Threads running: %02d.  Press 'A' to start a thread,'Q' to quit.", ThreadNum );
    SetConsoleTitle( NThreadMsg );
}

void ClearScreen( void )
{
    DWORD    dummy;
    COORD    Home = { 0, 0 };
    FillConsoleOutputCharacter( hConsoleOut, ' ', csbiInfo.dwSize.X * csbiInfo.dwSize.Y, Home, &dummy );
}


Writing a Multithreaded Win32 Program

Home | Overview | How Do I | Sample

When you write a program with multiple threads, you must coordinate their behavior and use of the program’s resources. You must also make sure that each thread receives its own stack.

Sharing Common Resources Between Threads

Note For a similar discussion from the MFC point of view, see Multithreading: Programming Tips and Multithreading: When to Use the Synchronization Classes.

Each thread has its own stack and its own copy of the CPU registers. Other resources, such as files, static data, and heap memory, are shared by all threads in the process. Threads using these common resources must be synchronized. Win32 provides several ways to synchronize resources, including semaphores, critical sections, events, and mutexes.

When multiple threads are accessing static data, your program must provide for possible resource conflicts. Consider a program where one thread updates a static data structure containing x,y coordinates for items to be displayed by another thread. If the update thread alters the x coordinate and is preempted before it can change the y coordinate, the display thread may be scheduled before the y coordinate is updated. The item would be displayed at the wrong location. You can avoid this problem by using semaphores to control access to the structure.

A mutex (short for mutual exclusion) is a way of communicating among threads or processes that are executing asynchronously of one another. This communication is usually used to coordinate the activities of multiple threads or processes, typically by controlling access to a shared resource by “locking” and “unlocking” the resource. To solve this x,y coordinate update problem, the update thread would set a mutex indicating that the data structure is in use before performing the update. It would clear the mutex after both coordinates had been processed. The display thread must wait for the mutex to be clear before updating the display. This process of waiting for a mutex is often called “blocking” on a mutex because the process is blocked and cannot continue until the mutex clears.

The BOUNCE.C program shown in the previous section uses a mutex named ScreenMutex to coordinate screen updates. Each time one of the display threads is ready to write to the screen, it calls WaitForSingleObject with the handle to ScreenMutex and constant INFINITE to indicate that the WaitForSingleObject call should block on the mutex and not time out. If ScreenMutex is clear, the wait function sets the mutex so other threads cannot interfere with the display and continues executing the thread. Otherwise, the thread blocks until the mutex clears. When the thread completes the display update, it releases the mutex by calling ReleaseMutex.

Screen displays and static data are only two of the resources requiring careful management. For example, your program may have multiple threads accessing the same file. Because another thread may have moved the file pointer, each thread must reset the file pointer before reading or writing. In addition, each thread must make sure that it is not preempted between the time it positions the pointer and the time it accesses the file. These threads should use a semaphore to coordinate access to the file by bracketing each file access with WaitForSingleObject and ReleaseMutex calls. The following code fragment illustrates this technique:

HANDLE    hIOMutex= CreateMutex (NULL, FALSE, NULL);

WaitForSingleObject( hIOMutex, INFINITE );
fseek( fp, desired_position, 0L );
fwrite( data, sizeof( data ), 1, fp );
ReleaseMutex( hIOMutex);

Thread Stacks

All of an application’s default stack space is allocated to the first thread of execution, which is known as thread 1. As a result, you must specify how much memory to allocate for a separate stack for each additional thread your program needs. The operating system will allocate additional stack space for the thread, if necessary, but you must specify a default value.

The first argument in the _beginthread call is a pointer to the BounceProc function, which will execute the threads. The second argument specifies the default stack size for the thread. The last argument is an ID number that is passed to BounceProc. BounceProc uses the ID number to seed the random number generator and to select the thread’s color attribute and display character.

Threads that make calls to the C run-time library or to the Win32 API must allow sufficient stack space for the library and API functions they call. The C printf function requires more than 500 bytes of stack space, and you should have 2K of stack space available when calling Win32 API routines.

Because each thread has its own stack, you can avoid potential collisions over data items by using as little static data as possible. Design your program to use automatic stack variables for all data that can be private to a thread. The only global variables in the BOUNCE.C program are either mutexes or variables that never change after they are initialized.

Win32 also provides Thread-Local Storage (TLS) to store per-thread data. See Thread Local Storage for more information.


Compiling and Linking Multithread Programs

Home | Overview | How Do I | Sample

To compile and link the multithread program BOUNCE.C from within the development environment

  1. Click New on the File menu, then click the Projects tab.

  2. On the Projects tab, click Console Application, and name the project.

  3. Add the file containing the C source code to the project.

  4. On the Project menu, click Settings. In the Project Settings dialog box, click the C/C++ tab. Select Code Generation from the Category drop-down list box. From the Use Run-Time Library drop-down box, select Multithreaded. Click OK.

  5. Build the project by clicking the Build command on the Build menu.

To compile and link the multithread program BOUNCE.C from the command line

  1. Ensure that the Win32 library files and LIBCMT.LIB are in the directory specified in your LIB environment variable.

  2. Compile and link the program with the CL command-line option /MT:
    CL /MT BOUNCE.C
  3. If you choose not to use the /MT option, you must take these steps:
    • Define the _MT symbol before including header files. You can do this by specifying /D _MT on the command line.

    • Specify the multithread library and suppress default library selection.

    The multithread include files are used when you define the symbolic constant _MT. You can do this with the CL command line option /D _MT or within the C source file before any include statements, as follows:

    #define _MT
#include <stdlib.h>


Avoiding Problem Areas with Multithread Programs

Home | Overview | How Do I | Sample

There are several problems you might encounter in creating, linking, or executing a multithread C program. Some of the more common ones are described here. (For a similar discussion from the MFC point of view, see Multithreading: Programming Tips.)

Problem | Probable cause
You get a message box showing that your program caused a protection violation. | Many Win32 programming errors cause protection violations. A common cause of protection violations is the indirect assignment of data to null pointers. This results in your program trying to access memory that does not “belong” to it, so a protection violation is issued. An easy way to detect the cause of a protection violation is to compile your program with debugging information, and then run it through the debugger in the Visual C++ environment. When the protection fault occurs, Windows transfers control to the debugger, and the cursor is positioned on the line that caused the problem.
Your program generates numerous compile and link errors. | If you attempt to compile and link a multithread program without defining the symbolic constant _MT, many of the definitions required for the multithread library will be missing. If you are using the Visual C++ development environment, make sure that the Project Settings dialog box specifies multithread libraries. From the command line, define _MT to CL with /MT or /D _MT, or use #define _MT in your program. You can eliminate many potential problems by setting the compiler’s warning level to one of its highest values and heeding the warning messages. By using the level 3 or level 4 warning level options, you can detect unintentional data conversions, missing function prototypes, and use of non-ANSI features.


Thread Local Storage (TLS)

Home | Overview | How Do I | Sample

Thread Local Storage (TLS) is the method by which each thread in a given multithreaded process may allocate locations in which to store thread-specific data. Dynamically bound (run-time) thread-specific data is supported by way of the TLS API (TlsAlloc, TlsGetValue, TlsSetValue, TlsFree). Win32 and the Visual C++ compiler now support statically bound (load-time) per-thread data in addition to the existing API implementation.

API Implementation for TLS

Thread Local Storage is implemented through the Win32 API layer as well as the compiler. For details, see the Win32 API documentation for TlsAlloc, TlsGetValue, TlsSetValue, and TlsFree.

The Visual C++ compiler includes a keyword to make thread local storage operations more automatic, rather than through the API layer. This syntax is described in the next section, Compiler Implementation for TLS.

Compiler Implementation for TLS

To support TLS, a new attribute, thread, has been added to the C and C++ languages and is supported by the Visual C++ compiler. This attribute is an extended storage class modifier, as described in the previous section. Use the __declspec keyword to declare a thread variable. For example, the following code declares an integer thread local variable and initializes it with a value:

__declspec( thread ) int tls_i = 1;

See Also Rules and Limitations for TLS


Rules and Limitations for TLS

The following guidelines must be observed when declaring statically bound thread local objects and variables:

  • The thread attribute can be applied only to data declarations and definitions. It cannot be used on function declarations or definitions. For example, the following code will generate a compiler error:
    #define Thread  __declspec( thread )
Thread void func();     // This will generate an error.
  • The thread modifier may be specified only on data items with static extent. This includes global data objects (both static and extern), local static objects, and static data members of C++ classes. Automatic data objects may not be declared with the thread attribute. The following code will generate compiler errors:
    #define Thread  __declspec( thread )
void func1()
{
    Thread int tls_i;            // This will generate an error.
}

int func2( Thread int tls_i )    // This will generate an error.
{
    return tls_i;
}
  • The declarations and the definition of a thread local object must all specify the thread attribute. For example, the following code will generate an error:
    #define Thread  __declspec( thread )
extern int tls_i;        // This will generate an error, since the
int Thread tls_i;        // declaration and definition differ.
  • The thread attribute cannot be used as a type modifier. For example, the following code will generate a compiler error:
    char __declspec( thread ) *ch;        // Error
  • C++ classes cannot use the thread attribute. However, C++ class objects may be instantiated with the thread attribute. For example, the following code will generate a compiler error:
    #define Thread  __declspec( thread )
class Thread C       // Error: classes cannot be declared Thread.
{
// Code
};
C CObject;

    Because the declaration of C++ objects that utilize the thread attribute is permitted, the following two examples are semantically equivalent:

    #define Thread  __declspec( thread )
Thread class B
{
// Code
} BObject;               // OK--BObject is declared thread local.

class B
{
// Code
};
Thread B BObject;        // OK--BObject is declared thread local.
  • Because C++ objects with constructors and destructors (as well as any object that utilizes some form of initialization semantics) may be allocated as thread local objects, an associated initialization routine (such as the constructor) is called to initialize that object. For example:
    class tlsClass
{
    private:
        int x;
    public:
        tlsClass() { x = 1; } ;
        ~tlsClass();
}

__declspec( thread ) tlsClass tlsObject;
extern int func();
__declspec( thread ) int y = func();

    In this case, data or objects initialized by the func routine do not necessarily belong to the same thread into which tlsObject is instantiated.

  • The address of a thread local object is not considered constant, and any expression involving such an address is not considered a constant expression. In standard C, the effect of this is to forbid the use of the address of a thread local variable as an initializer for an object or pointer. For example, the following code will be flagged as an error by the C compiler:
    #define Thread  __declspec( thread )
Thread int tls_i;
int *p = &tls_i;        //This will generate an error in C.

    This restriction does not apply in C++, however. Because C++ permits dynamic initialization of all objects, you can initialize an object with an expression that uses the address of a thread local variable. This is accomplished in the same way as the construction of thread local objects. For example, the code shown above will not generate an error when compiled as a C++ source file. Note that the address of a thread local variable is valid only as long as the thread in which the address was taken still exists.

  • Standard C permits the initialization of an object or variable with an expression involving a reference to itself, but only for objects of nonstatic extent. Although C++ normally permits such dynamic initialization of objects with an expression involving a reference to itself, this type of initialization is not permitted with thread local objects. For example:
    #define Thread  __declspec( thread )
Thread int tls_i = tls_i;                // Error in C and C++
int j = j;                               // OK in C++, error in C
Thread int tls_i = sizeof( tls_i )       // Legal in C and C++

    Note that a sizeof expression that includes the object being initialized does not constitute a reference to itself, and is legal in both C and C++.

    C++ does not allow such dynamic initialization of thread data because of possible future enhancements to the thread local storage facility.

  • If a DLL declares any nonlocal data or object as __declspec( thread ), it can cause a protection fault if dynamically loaded. After the DLL is loaded with LoadLibrary, it causes system failure whenever the code references the nonlocal __declspec( thread ) data. Because the global variable space for a thread is allocated at run time, the size of this space is based on a calculation of the requirements of the application plus the requirements of all of the DLLs that are statically linked. When you use LoadLibrary, there is no way to extend this space to allow for the thread local variables declared with __declspec( thread ). Use the TLS APIs, such as TlsAlloc, in your DLL to allocate TLS if the DLL might be loaded with LoadLibrary.


Multithreading with C++ and MFC

Home | Overview | How Do I | Sample

The Microsoft Foundation Class Library (MFC) provides support for multithreaded applications. This article describes what processes and threads are, and MFC’s approach to multithreading.

A “process” is an executing instance of an application. For example, when you double-click the Notepad icon, you start a process that runs Notepad.

A “thread” is a path of execution within a process. When you start Notepad, the operating system creates a process and begins executing the primary thread of that process. When this thread terminates, so does the process. This primary thread is supplied to the operating system by the startup code in the form of a function address. Usually, it is the address of the main or WinMain function that is supplied.

You can create additional threads in your application if you wish. You may want to do this to handle background or maintenance tasks when you don’t want the user to wait for them to complete. All threads in MFC applications are represented by CWinThread objects. In most situations, you don’t even have to explicitly create these objects; instead call the framework helper function AfxBeginThread, which creates the CWinThread object for you.

MFC distinguishes two types of threads: user-interface threads and worker threads. User-interface threads are commonly used to handle user input and respond to events and messages generated by the user. Worker threads are commonly used to complete tasks, such as recalculation, that do not require user input. The Win32 API does not distinguish between types of threads; it just needs to know the thread’s starting address so it can begin to execute the thread. MFC handles user-interface threads specially by supplying a message pump for events in the user interface. CWinApp is an example of a user-interface thread object, as it derives from CWinThread and handles events and messages generated by the user.

Special attention should be given to situations where more than one thread may require access to the same object. The article Multithreading: Programming Tips describes techniques you can use to get around problems that may arise in these situations. The article Multithreading: How to Use the Synchronization Classes describes how to use the classes that are available to synchronize access from multiple threads to a single object.

Writing and debugging multithreaded programming is inherently a complicated and tricky undertaking, as you must ensure that objects are not accessed by more than one thread at a time. The articles in the Multithreading group do not teach the basics of multithreaded programming, only how to use MFC in your multithreaded program. The multithreaded MFC samples included in Visual C++ illustrate a few multithreaded programming techniques and Win32 APIs not encompassed by MFC, but are only intended to be a starting point.

For more information on how the operating system handles processes and threads, see Processes and Threads, in the Win32 Programmer’s Reference of the Win32 SDK.

To gain an understanding of how to write a multithreaded program, you should refer to a book such as Jeffrey Richter’s Advanced Windows NT (Microsoft Press, 1994).

For more details on MFC multithreading support, see the following articles:

  • Multithreading: Creating User-Interface Threads

  • Multithreading: Creating Worker Threads

  • Multithreading: How to Use the Synchronization Classes

  • Multithreading: Terminating Threads

  • Multithreading: Programming Tips

  • Multithreading: When to Use the Synchronization Classes


Multithreading: Creating User-Interface Threads

Home | Overview | How Do I | Sample

A user-interface thread is commonly used to handle user input and respond to user events independently of threads executing other portions of the application. The main application thread (provided in your CWinApp-derived class) is already created and started for you. This article describes the steps necessary to create additional user-interface threads.

The first thing you must do when creating a user-interface thread is derive a class from CWinThread. You must declare and implement this class, using the DECLARE_DYNCREATE and IMPLEMENT_DYNCREATE macros. This class must override some functions, and can override others. These functions and what they should do are presented in the following table.

Functions to Override When Creating a User-Interface Thread

Function name | Purpose
ExitInstance | Perform cleanup when thread terminates. Usually overridden.
InitInstance | Perform thread instance initialization. Must be overridden.
OnIdle | Perform thread-specific idle-time processing. Not usually overridden.
PreTranslateMessage | Filter messages before they are dispatched to TranslateMessage and DispatchMessage. Not usually overridden.
ProcessWndProcException | Intercept unhandled exceptions thrown by the thread’s message and command handlers. Not usually overridden.
Run | Controlling function for the thread. Contains the message pump. Rarely overridden.

MFC provides two versions of AfxBeginThread through parameter overloading: one for user-interface threads and the other for worker threads. To start your user-interface thread, call AfxBeginThread, providing the following information:

  • The RUNTIME_CLASS of the class you derived from CWinThread.

  • (Optional) The desired priority level. The default is normal priority. For more information on the available priority levels, see SetThreadPriority in the Win32 Programmer’s Reference.

  • (Optional) The desired stack size for the thread. The default is the same size stack as the creating thread.

  • (Optional) CREATE_SUSPENDED if you want the thread to be created in a suspended state. The default is 0, or start the thread normally.

  • (Optional) The desired security attributes. The default is the same access as the parent thread. For more information on the format of this security information, see SECURITY_ATTRIBUTES in the Win32 Programmer’s Reference.

AfxBeginThread does most of the work for you. It creates a new object of your class, initializes it with the information you supply, and calls CWinThread::CreateThread to start executing the thread. Checks are made throughout the procedure to make sure all objects are deallocated properly should any part of the creation fail.

What do you want to know more about?

  • Multithreading: Terminating Threads

  • Multithreading: Creating Worker Threads

  • Processes and Threads (in the Win32 Programmer’s Reference)


Multithreading: Creating Worker Threads

Home | Overview | How Do I | Sample

A worker thread is commonly used to handle background tasks that the user shouldn’t have to wait for to continue using your application. Tasks such as recalculation and background printing are good examples of worker threads. This article details the steps necessary to create a worker thread. Topics include:

  • Starting the thread

  • Implementing the controlling function

  • Example

Creating a worker thread is a relatively simple task. Only two steps are required to get your thread running: implementing the controlling function and starting the thread. It is not necessary to derive a class from CWinThread. You can if you need a special version of CWinThread, but it is not required for most simple worker threads. You can use CWinThread without modification.

Starting the Thread

There are two overloaded versions of AfxBeginThread: one for user-interface threads and one for worker threads. To begin execution of your worker thread, call AfxBeginThread providing the following information:

  • The address of the controlling function.

  • The parameter to be passed to the controlling function.

  • (Optional) The desired priority of the thread. The default is normal priority. For more information on the available priority levels, see ::SetThreadPriority in the Win32 Programmer’s Reference.

  • (Optional) The desired stack size for the thread. The default is the same size stack as the creating thread.

  • (Optional) CREATE_SUSPENDED if you want the thread to be created in a suspended state. The default is 0, or start the thread normally.

  • (Optional) The desired security attributes. The default is the same access as the parent thread. For more information on the format of this security information, see SECURITY_ATTRIBUTES in the Win32 Programmer’s Reference.

AfxBeginThread creates and initializes a CWinThread object for you, starts it, and returns its address so you can refer to it later. Checks are made throughout the procedure to make sure all objects are deallocated properly should any part of the creation fail.

Implementing the Controlling Function

The controlling function defines the thread. When this function is entered, the thread starts, and when it exits, the thread terminates. This function should have the following prototype:

UINT MyControllingFunction( LPVOID pParam );

The parameter is a single 32-bit value. The value the function receives in this parameter is the value that was passed to the constructor when the thread object was created. The controlling function can interpret this value in any manner it chooses. It can be treated as a scalar value, or a pointer to a structure containing multiple parameters, or it can be ignored. If the parameter refers to a structure, the structure can be used not only to pass data from the caller to the thread, but also to pass data back from the thread to the caller. If you use such a structure to pass data back to the caller, the thread will need to notify the caller when the results are ready. For information on communicating from the worker thread to the caller, see the article Multithreading: Programming Tips.

When the function terminates, it should return a UINT value indicating the reason for termination. Typically, this exit code is 0 to indicate success with other values indicating different types of errors. This is purely implementation dependent. Some threads may maintain usage counts of objects, and return the current number of uses of that object. To see how applications can retrieve this value, see the article Multithreading: Terminating Threads.

There are some restrictions on what you can do in a multithreaded program written with the Microsoft Foundation Class Library. For descriptions of these restrictions and other tips on using threads, see the article Multithreading: Programming Tips.

Controlling Function Example

This example shows how to define a controlling function and use it from another portion of the program.

UINT MyThreadProc( LPVOID pParam )
{
    CMyObject* pObject = (CMyObject*)pParam;

    if (pObject == NULL ||
        !pObject->IsKindOf(RUNTIME_CLASS(CMyObject)))
    return 1;   // if pObject is not valid

    // do something with 'pObject'

    return 0;   // thread completed successfully
}

// inside a different function in the program
.
.
.
pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);
.
.
.

What do you want to know more about?

  • Multithreading: Creating User-Interface Threads


Multithreading: When to Use the Synchronization Classes

Home | Overview | How Do I | Sample

The six multithreaded classes provided with MFC fall into two categories: synchronization objects (CSyncObject, CSemaphore, CMutex, CCriticalSection, and CEvent) and synchronization access objects (CMultiLock and CSingleLock).

Synchronization classes are used when access to a resource must be controlled to ensure integrity of the resource. Synchronization access classes are used to gain access to these controlled resources. This article describes when to use each class.

To determine which synchronization class you should use, ask the following series of questions:

  1. Does the application have to wait for something to happen before it can access the resource (for example, data must be received from a communications port before it can be written to a file)?

    If yes, use CEvent.

  2. Can more than one thread within the same application access this resource at one time (for example, your application allows up to five windows with views on the same document)?

    If yes, use CSemaphore.

  3. Can more than one application use this resource (for example, the resource is in a DLL)?

    If yes, use CMutex.

    If no, use CCriticalSection.

CSyncObject is never used directly. It is the base class for the other four synchronization classes.

Example 1: Using Three Synchronization Classes

As an example, take an application that maintains a linked list of accounts. This application allows up to three accounts to be examined in separate windows, but only one can be updated at any particular time. When an account is updated, the updated data is sent over the network to a data archive.

This example application uses all three types of synchronization classes. Because it allows up to three accounts to be examined at one time, it uses CSemaphore to limit access to three view objects. When an attempt to view a fourth account occurs, the application either waits until one of the first three windows closes or it fails. When an account is updated, the application uses CCriticalSection to ensure that only one account is updated at a time. After the update succeeds, it signals CEvent, which releases a thread waiting for the event to be signaled. This thread sends the new data to the data archive.

Example 2: Using Synchronization Access Classes

Choosing which synchronization access class to use is even simpler. If your application is concerned with accessing a single controlled resource only, use CSingleLock. If it needs access to any one of a number of controlled resources, use CMultiLock. In example 1, CSingleLock would have been used, as in each case only one resource was needed at any particular time.

For example code that uses the synchronization classes, see the MFC sample programs MTGDI and MUTEXES. These and other MFC sample programs can be found in Visual C++ Samples.

For information on how the synchronization classes are used, see the article Multithreading: How to Use the Synchronization Classes. For more information on synchronization, see Synchronization in the Win32 Programmer’s Reference of the Win32 SDK. For more information on multithreading support in MFC, see the article Multithreading with C++ and MFC.


Multithreading: How to Use the Synchronization Classes

Home | Overview | How Do I | Sample

Synchronizing resource access between threads is a common problem when writing multithreaded applications. Having two or more threads simultaneously access the same data can lead to undesirable and unpredictable results. For example, one thread could be updating the contents of a structure while another thread is reading the contents of the same structure. It is unknown what data the reading thread will receive: the old data, the newly written data, or possibly a mixture of both. MFC provides a number of synchronization and synchronization access classes to aid in solving this problem. This article explains the classes available and how to use them to create thread-safe classes in a typical multithreaded application.

A typical multithreaded application has a class that represents a resource to be shared among threads. A properly designed, fully thread-safe class does not require you to call any synchronization functions. Everything is handled internally to the class, allowing you to concentrate on how to best use the class, not about how it might get corrupted. The best technique for creating a fully thread-safe class is to merge the synchronization class into the resource class. Merging the synchronization classes into the shared class is a straightforward process.

As an example, take an application that maintains a linked list of accounts. This application allows up to three accounts to be examined in separate windows, but only one can be updated at any particular time. When an account is updated, the updated data is sent over the network to a data archive.

This example application uses all three types of synchronization classes. Because it allows up to three accounts to be examined at one time, it uses CSemaphore to limit access to three view objects. When an attempt to view a fourth account occurs, the application either waits until one of the first three windows closes or it fails. When an account is updated, the application uses CCriticalSection to ensure that only one account is updated at a time. After the update succeeds, it signals CEvent, which releases a thread waiting for the event to be signaled. This thread sends the new data to the data archive.

Designing a Thread-Safe Class

To make a class fully thread-safe, first add the appropriate synchronization class to the shared classes as a data member. In the previous account-management example, a CSemaphore data member would be added to the view class, a CCriticalSection data member would be added to the linked-list class, and a CEvent data member would be added to the data storage class.

Next, add synchronization calls to the appropriate member functions of each thread-safe class. This means that all member functions that modify the data in the class or access a controlled resource should create either a CSingleLock or CMultiLock object and call that object’s Lock function. When the lock object goes out of scope and is destroyed, the object’s destructor calls Unlock for you, releasing the resource. Of course, you can call Unlock directly if you wish.

Designing your thread-safe class in this fashion allows it to be used in a multithreaded application as easily as a non-thread-safe class, but with complete safety. Encapsulating the synchronization object and synchronization access object into the resource’s class provides all the benefits of fully thread-safe programming without the drawback of maintaining synchronization code.

The drawbacks to this approach are that the class will be slightly slower than the same class without the synchronization objects added. Also, if there is a chance that more than one thread may delete the object, the merged approach might not always work. In this situation, it is better to maintain separate synchronization objects.

For example code that uses the synchronization classes, see the MFC sample programs MTGDI and MUTEXES. These and other MFC sample programs can be found in Visual C++ Samples.

For information on determining which synchronization class to use in different situations, see the article Multithreading: When to Use the Synchronization Classes. For more information on synchronization, see Synchronization in the Win32 Programmer’s Reference of the Win32 SDK. For more information on multithreading support in MFC, see the article Multithreading with C++ and MFC.


Multithreading: Terminating Threads

Home | Overview | How Do I | Sample

Two normal situations cause a thread to terminate: The controlling function exits or the thread is not allowed to run to completion. If a word processor used a thread for background printing, the controlling function would terminate normally if printing completed successfully. Should the user wish to cancel the printing, however, the background printing thread would have to be terminated prematurely. This article explains both how to implement each situation and how to get the exit code of a thread after it terminates.

  • Normal Thread Termination

  • Premature Thread Termination

  • Retrieving the Exit Code of a Thread

Normal Thread Termination

For a worker thread, normal thread termination is simple: Exit the controlling function and return a value that signifies the reason for termination. You can use either the AfxEndThread function or a return statement. Typically, 0 signifies successful completion, but that is up to you.

For a user-interface thread, the process is just as simple: from within the user-interface thread, call ::PostQuitMessage in the Win32 Programmer’s Reference, Volume 4. The only parameter that ::PostQuitMessage takes is the exit code of the thread. As for worker threads, 0 typically signifies successful completion.

Premature Thread Termination

Terminating a thread prematurely is almost as simple: Call AfxEndThread from within the thread. Pass the desired exit code as the only parameter. This stops execution of the thread, deallocates the thread’s stack, detaches all DLLs attached to the thread, and deletes the thread object from memory.

AfxEndThread must be called from within the thread to be terminated. If you want to terminate a thread from another thread, you must set up a communication method between the two threads.

Retrieving the Exit Code of a Thread

To get the exit code of either the worker or the user-interface thread, call the ::GetExitCodeThread function. For information about this function, see the Win32 Programmer’s Reference, Volume 3. This function takes the handle to the thread (stored in the m_hThread data member of CWinThread objects) and the address of a DWORD.

If the thread is still active, ::GetExitCodeThread will place STILL_ACTIVE in the supplied DWORD address; otherwise, the exit code is placed in this address.

Retrieving the exit code of CWinThread objects takes an extra step. By default, when a CWinThread thread terminates, the thread object is deleted. This means you cannot access the m_hThread data member because the CWinThread object no longer exists. To avoid this situation, do one of the following two things:

  • Set the m_bAutoDelete data member to FALSE. This allows the CWinThread object to survive after the thread has been terminated. You can then access the m_hThread data member after the thread has been terminated. If you use this technique, however, you are responsible for destroying the CWinThread object as the framework will not automatically delete it for you. This is the preferred method.

    -or-

  • Store the thread’s handle separately. After the thread is created, copy its m_hThread data member (using ::DuplicateHandle) to another variable and access it through that variable. This way the object is deleted automatically upon termination and you can still find out why the thread terminated. Be careful that the thread does not terminate before you can duplicate the handle. The safest way to do this is to pass CREATE_SUSPENDED to AfxBeginThread, store the handle, and then resume the thread by calling ResumeThread.

Either method allows you to determine why a CWinThread object terminated.

See Also _endthreadex, _beginthreadex, ::ExitThread


Multithreading: Programming Tips

Home | Overview | How Do I | Sample

Multithreaded applications require stricter care than single-threaded applications when accessing data. Because there are multiple, independent paths of execution in use simultaneously in multithreaded applications, either the algorithms, the data, or both must be aware that data could be used by more than one thread at a time. This article explains techniques for avoiding potential problems when programming multithreaded applications with the Microsoft Foundation Class Library (MFC).

  • Accessing Objects from Multiple Threads

  • Accessing MFC Objects from Non-MFC Threads

  • Windows Handle Maps

  • Communicating Between Threads

Accessing Objects from Multiple Threads

For size and performance reasons, MFC objects are not thread-safe at the object level, only at the class level. This means that you can have two separate threads manipulating two different CString objects, but not two threads manipulating the same CString object. If you absolutely must have multiple threads manipulating the same object, protect such access with appropriate Win32 synchronization mechanisms, such as critical sections. For more information on critical sections and other related objects, see Synchronization in the Win32 SDK.

The class library uses critical sections internally to protect global data structures, such as those used by the debug memory allocation.

Accessing MFC Objects from Non-MFC Threads

If you have a multithreaded application that creates a thread in a way other than using a CWinThread object, you cannot access other MFC objects from that thread. In other words, if you want to access any MFC object from a secondary thread, you must create that thread with one of the methods described in the Multithreading: Creating User-Interface Threads or Multithreading: Creating Worker Threads articles. These methods are the only ones that allow the class library to initialize the internal variables necessary to handle multithreaded applications.

Windows Handle Maps

As a general rule, a thread can access only MFC objects that it created. This is because temporary and permanent Windows handle maps are kept in thread local storage to ensure protection from simultaneous access from multiple threads. For example, a worker thread cannot perform a calculation and then call a document’s UpdateAllViews member function to have the windows that contain views on the new data modified. This will have no effect at all, because the map from CWnd objects to HWNDs is local to the primary thread. This means that one thread may have a mapping from a Windows handle to a C++ object, but another thread may map that same handle to a different C++ object. Changes made in one thread would not be reflected in the other.

There are several ways around this problem. The first is to pass individual handles (such as an HWND) rather than C++ objects to the worker thread. The worker thread then adds these objects to its temporary map by calling the appropriate FromHandle member function. You could also add the object to the thread’s permanent map by calling Attach, but this should be done only if you are guaranteed that the object will exist longer than the thread.

Another method is to create new user-defined messages corresponding to the different tasks your worker threads will be performing and post these messages to the application’s main window using ::PostMessage. This method of communication is similar to two different applications conversing except that both threads are executing in the same address space.

For more information on handle maps, see Technical Note 3. For more information on thread local storage, see Thread Local Storage and Using Thread Local Storage in the Win32 Programmer’s Reference.

Communicating Between Threads

MFC provides a number of classes that allow threads to synchronize access to objects to maintain thread safety. Usage of these classes is described in the articles Multithreading: How to Use the Synchronization Classes and Multithreading: When to Use the Synchronization Classes. More information on these objects can be found in Synchronization in the Win32 Programmer’s Reference.


OLE Topics

Home | Overview | How Do I | Sample | Tutorial

This family of articles explains the fundamentals of OLE programming using MFC.

Note OLE vs. Active technology: The name OLE denotes the technologies associated with linking and embedding, including OLE containers, OLE servers, OLE items, in-place activation (or visual editing), trackers, drag and drop, menu merging. The term Active applies to the Component Object Model (COM) and COM-based objects such as ActiveX controls. OLE Automation is now called Automation.

What do you want to know more about?

  • What OLE is all about, and the various OLE technologies.

  • Activation

  • Automation

  • Automation Clients

  • Automation Servers

  • Connection Points

  • Containers

  • Data objects and data sources: OLE uniform data transfer.

  • Drag and drop.

  • OLE menus and resources

  • Remote Automation

  • Registration.

  • Servers

  • Trackers


OLE Background

Home | Overview | How Do I | Sample | Tutorial

OLE is a mechanism that allows users to create and edit documents containing items or “objects” created by multiple applications.

Note OLE was originally an acronym for Object Linking and Embedding. However, it is now referred to simply as OLE. Parts of OLE not related to linking and embedding are now part of Active technology.

OLE documents, historically called compound documents, seamlessly integrate various types of data, or components. Sound clips, spreadsheets, and bitmaps are typical examples of components found in OLE documents. Supporting OLE in your application allows your users to use OLE documents without worrying about switching between the different applications; OLE does the switching for you.

You use a container application to create compound documents and a server application or component application to create the items within the container document. Any application you write can be a container, a server, or both.

OLE incorporates many different concepts that all work toward the goal of seamless interaction between applications. These areas include the following:

Linking and Embedding

Linking and Embedding are the two methods for storing items created inside an OLE document that were created in another application. For general information on the differences between the two, see the article OLE Background: Linking and Embedding. For more detailed information, see the articles Containers and Servers.

In-Place Activation (Visual Editing)

Activating an embedded item in the context of the container document is called in-place activation or visual editing. The container application’s interface changes to incorporate the features of the component application that created the embedded item. Linked items are never activated in-place because the actual data for the item is contained in a separate file, out of the context of the application containing the link. For more information on in-place activation, see the article Activation.

Note Linking and embedding and in-place activation provide the main features of OLE visual editing.

Automation

Automation allows one application to drive another application. The driving application is known as an automation client or automation controller, and the application being driven is known as an automation server or automation component. For more information on automation, see the articles Automation Clients and Automation Servers.

Note Automation works in both OLE and Active technology contexts. You can automate any object based on COM.

Compound Files

Compound files provide a standard file format that simplifies structured storing of compound documents for OLE applications. Within a compound file, storages have many features of directories and streams have many features of files. This technology is also called structured storage. For more information on compound files, see the article Containers: Compound Files.

Uniform Data Transfer

Uniform Data Transfer (UDT) is a set of interfaces that allow data to be sent and received in a standard fashion, regardless of the actual method chosen to transfer the data. UDT forms the basis for data transfers by drag and drop. UDT now serves as the basis for existing Windows data transfer, such as the Clipboard and dynamic data exchange (DDE). For more information on UDT, see the article Data Objects and Data Sources (OLE).

Drag and Drop

Drag and drop is an easy-to-use, direct-manipulation technique to transfer data between applications, between windows within an application, or even within a single window in an application. The data to be transferred is simply selected and dragged to the desired destination. Drag and drop is based on uniform data transfer. For more information on drag and drop, see the article Drag and Drop.

Component Object Model

The Component Object Model (COM) provides the infrastructure used when OLE objects communicate with each other. The MFC OLE classes simplify COM for the programmer. COM is part of Active technology, as COM objects underlie both OLE and Active technology. For more information about COM, see the OLE Programmer’s Reference and the Active Template Library (ATL) Reference.

Some of the more important OLE topics are covered in the following articles:

  • OLE Background: Linking and Embedding

  • OLE Background: Containers and Servers

  • OLE Background: Implementation Strategies

  • OLE Background: MFC Implementation

For information about handling context-sensitive Help in OLE applications, see the article Help: OLE Support for Help.

For general OLE information not found in the above articles, see the OLE Programmer’s Reference. Another good source of information is Kraig Brockschmidt’s book Inside OLE (Microsoft Press, 1995, second edition).


OLE Background: Linking and Embedding

Home | Overview | How Do I | Sample | Tutorial

This article defines the OLE terms “linking” and “embedding.”

Using the Paste command in a container application can create an embedded component, or embedded item. The source data for an embedded item is stored as part of the OLE document that contains it. In this way, a document file for a word processor document can contain not only text, but also bitmaps, graphs, formulas, or any other type of data.

OLE provides another way to incorporate data from another application: creating a linked component, or linked item, or simply a link. The steps for creating a linked item are similar to those for creating an embedded item, except that you use the Paste Link command instead of the Paste command. Unlike an embedded component, a linked component stores a path to the original data, which is often in a separate file.

For example, if you are working in a word processor document and create a linked item to some spreadsheet cells, the data for the linked item is stored in the original spreadsheet document. The word processor document contains only the information specifying where the item can be found; that is, it contains a link to the original spreadsheet document. When you double-click the cells, the spreadsheet application is launched and the original spreadsheet document is loaded from where it was stored.

Every OLE item, whether embedded or linked, has a type associated with it based on the application that created it. For example, a Microsoft Paintbrush item is one type of item, while a Microsoft Excel item is another type. Some applications, however, can create more than one item type. For example, Microsoft Excel can create worksheet items, chart items, and macrosheet items. Each of these items can be uniquely identified by the system using a Class Identifier or CLSID.

For more information on the kind of data stored in embedded and linked items, see the OLE Programmer’s Reference.

See Also OLE Background: Containers and Servers, Containers: Client Items, Servers: Server Items


OLE Background: Containers and Servers

Home | Overview | How Do I | Sample | Tutorial

This article defines and explains container and server applications.

A container application is an application that can incorporate embedded or linked items into its own documents. The documents managed by a container application must be able to store and display OLE document components as well as the data created by the application itself. A container application must also allow users to insert new items or edit existing items by activating server applications when necessary. The user-interface requirements of a container application are listed in the article Containers: User-Interface Issues.

A server application or component application is an application that can create OLE document components for use by container applications. Server applications usually support drag and drop or copying their data to the Clipboard so that a container application can insert the data as an embedded or linked item. An application can be both a container and a server.

Most servers are stand-alone applications or full-servers; they can either be run as stand-alone applications or can be launched by a container application. A mini-server is a special type of server application that can be launched only by a container. It cannot be run as a stand-alone application. Microsoft Draw and Microsoft Graph servers are examples of mini-servers.

Containers and servers do not communicate directly. Instead, they communicate through the OLE system DLLs. These DLLs provide functions that containers and servers call, and the containers and servers provide callback functions that the DLLs call.

Using this means of communication, a container doesn’t need to know the implementation details of the server application. It allows a container to accept items created by any server without having to define the types of servers with which it can work. As a result, the user of a container application can take advantage of future applications and data formats. As long as these new applications are OLE components, a compound document will be able to incorporate items created by those applications.

See Also OLE Background: MFC Implementation, Containers, Servers, Containers: Client Items, Servers: Server Items


OLE Background: Implementation Strategies

Home | Overview | How Do I | Sample | Tutorial

Depending on your application, there are four possible implementation strategies for adding OLE support:

  • You are writing a new application.

    This situation usually requires the least work. You simply run AppWizard and select OLE options to create a skeleton application. For information on the OLE options in AppWizard and what they do, see the article The MFC AppWizard (EXE version): Step-by-Step.

  • You have a program written with the Microsoft Foundation Class Library version 2.0 or higher that does not support OLE.

    Create a new application with AppWizard as above, then copy and paste the code from the new application into your existing application. This will work for servers, containers, or automated applications. See the MFC Tutorial sample, SCRIBBLE, Step 7, and the Scribble Step 7 tutorial for an example of this strategy.

  • You have a Microsoft Foundation Class Library program that implements OLE version 1.0 support.

    See MFC Technical Note 41 for this conversion strategy.

  • You have an application that was not written using the Microsoft Foundation classes and that may or may not have implemented OLE support.

    This situation requires the most work. One approach is to create a new application, as in the first strategy, then copy and paste your existing code into it. If your existing code is written in C, you may need to modify it so it can compile as C++ code. If your C code calls the Windows API, you do not have to change it to use the Microsoft Foundation classes. This approach likely will require some restructuring of your program to support the document/view architecture used by versions 2.0 and higher of the Microsoft Foundation classes. For more information on this architecture, see Technical Note 25, and see the MFC Migration Kit, which contains the MFC Migration Guide.

Once you have decided on a strategy, you should either read the Containers or Servers family of articles (depending on the type of application you are writing), or examine the sample programs, or both. The MFC OLE samples OCLIENT and HIERSVR show how to implement the various aspects of containers and servers, respectively. At various points throughout these articles, you will be referred to certain functions in these samples as examples of the techniques being discussed.

See Also Containers: Implementing a Container, Servers: Implementing a Server, The MFC AppWizard (EXE version): Step-by-Step


OLE Background: MFC Implementation

Home | Overview | How Do I | Sample | Tutorial

Because of the size and complexity of the raw OLE API, calling it directly to write OLE applications can be very time-consuming. The goal of the Microsoft Foundation Class Library implementation of OLE is to reduce the amount of work you have to do to write full-featured, OLE-capable applications.

This article explains the parts of the OLE API that have not been implemented inside MFC. The discussion also explains how what is implemented maps to the OLE section of the Win32 SDK.

Portions of OLE Not Implemented by the Class Library

There are a few interfaces and features of OLE not directly provided by MFC. If you want to use these features, you can call the OLE API directly.

IMoniker Interface

The IMoniker interface is implemented by the class library (for example, the COleServerItem class), but has not previously been exposed to the programmer. For more information about this interface, see OLE Moniker Implementations in the OLE section of the Win32 SDK. However, see also class CMonikerFile and CAsyncMonikerFile.

IUnknown and IMarshal Interfaces

The IUnknown interface is implemented by the class library, but is not exposed to the programmer. The IMarshal interface is not implemented by the class library, but is used internally. Automation servers built using the class library already have marshalling capabilities built in. For more information about these interfaces, see the OLE Programmer’s Reference.

Docfiles (Compound Files)

Compound files are partially supported by the class library. None of the functions that directly manipulate compound files beyond creation are supported. MFC uses class COleFileStream to support manipulation of streams with standard file functions. For more information, see the article Containers: Compound Files.

In-Process Servers and Object Handlers

In-process servers and object handlers allow implementation of visual editing data or full component object model (COM) objects in a DLL. To do this, you can implement your DLL by calling the OLE API directly. However, if you are writing an Automation server and your server has no user interface, you can use AppWizard to make your server an in-process server and put it completely into a DLL. For more information about these topics, see the article Automation Servers and also The OLE Messaging Library: An Automation Server in the Win32 SDK.

Tip The easiest way to implement an Automation server is to place it in a DLL. MFC supports this approach.

For detailed information on how the Microsoft Foundation OLE classes implement OLE interfaces, see MFC Technical Notes 38, 39, and 40.

See Also OLE Background: Implementation Strategies


Activation

Home | Overview | How Do I | Sample | Tutorial

This article explains the role of activation in the visual editing of OLE items. After a user has embedded an OLE item in a container document, it may need to be used. To do this, the user double-clicks the item, which activates that item. The most frequent activity for activation is editing. Many current OLE items, when activated for editing, cause the menus and toolbars in the current frame window to change to reflect those belonging to the server application that created the item. This behavior, known as in-place activation, allows the user to edit any embedded item in a compound document without leaving the container document’s window.

It is also possible to edit embedded OLE items in a separate window. This will happen if either the container or server application does not support in-place activation. In this case, when the user double-clicks an embedded item, the server application is launched in a separate window and the embedded item appears as its own document. The user edits the item in this window. When editing is complete, the user closes the server application and returns to the container application.

As an alternative, the user can choose “open editing” with the <object> Open command on the Edit menu. This opens the object in a separate window.

Note Editing embedded items in a separate window was standard behavior in version 1 of OLE, and some OLE applications may support only this style of editing.

In-place activation promotes a document-centric approach to document creation. The user can treat a compound document as a single entity, working on it without switching between applications. However, in-place activation is used only for embedded items, not for linked items: they must be edited in a separate window. This is because a linked item is actually stored in a different place. The editing of a linked item takes place within the actual context of the data, that is, where the data is stored. Editing a linked item in a separate window reminds the user that the data belongs to another document.

MFC does not support nested in-place activation. If you build a container/server application, and that container/server is embedded in another container and in-place activated, it cannot in-place activate objects embedded inside it.

What happens to an embedded item when the user double-clicks it depends on the verbs defined for the item. See Activation: Verbs.

See Also Containers, Servers


Activation: Verbs

Home | Overview | How Do I | Sample | Tutorial

This article explains the role primary and secondary verbs play in OLE activation.

Usually, double-clicking an embedded item allows the user to edit it. However, certain items don’t behave this way. For example, double-clicking an item created with the Sound Recorder application does not open the server in a separate window; instead, it plays the sound.

The reason for this behavior difference is that Sound Recorder items have a different “primary verb.” The primary verb is the action performed when the user double-clicks an OLE item. For most types of OLE items, the primary verb is Edit, which launches the server that created the item. For some types of items, such as Sound Recorder items, the primary verb is Play.

Many types of OLE items support only one verb, and Edit is the most common one. However, some types of items support multiple verbs. For example, Sound Recorder items support Edit as a secondary verb.

Another verb used frequently is Open. The Open verb is identical to Edit, except the server application is launched in a separate window. This verb should be used when either the container application or the server application does not support in-place activation.

Any verbs other than the primary verb must be invoked through a submenu command when the item is selected. This submenu contains all the verbs supported by the item and is usually reached by the typename Object command on the Edit menu. For information on the typename Object command, see the article Menus and Resources: Container Additions.

The verbs a server application supports are listed in the Windows registration database. If your server application is written with the Microsoft Foundation Class Library, it will automatically register all verbs when the server is started. If not, you should register them during the server application’s initialization phase. For more information, see the article Registration.

See Also Activation, Containers, Servers


Containers

Home | Overview | How Do I | Sample | Tutorial

A container application is an application that can incorporate embedded or linked items into its own documents. The documents managed by a container application must be able to store and display OLE compound document components as well as data created by the application itself. A container application must also allow users to insert new items or edit existing items. Creating an OLE Container in Tutorials takes you through the process of creating a container application. You should complete that tutorial before reading this family of articles.

What do you want to do?

  • Implement a container

  • Learn about container client items

  • Use compound files

  • Learn about container user-interface issues

  • Learn about advanced features of containers

See Also Servers, Activation, Menus and Resources (OLE)


Containers: Implementing a Container

Home | Overview | How Do I | Sample | Tutorial

Creating an OLE Container in Tutorials describes the implementation of a simple visual editing container, CONTAINER, explaining each step in detail. This article summarizes the tutorial procedure and points you to other articles that provide more detailed explanations about implementing containers. It also lists some optional OLE features you may want to implement and the articles describing these features.

To prepare your CWinApp-derived class

  1. Initialize the OLE libraries by calling AfxOleInit in the InitInstance member function.

  2. Call CDocTemplate::SetContainerInfo in InitInstance to assign the menu and accelerator resources used when an embedded item is activated in-place. For more information on this topic, see the Activation article.

These features are provided for you automatically when you use AppWizard to create a container application. See the article The MFC AppWizard (EXE version): Step-by-Step.

To prepare your view class

  1. Keep track of selected items by maintaining a pointer, or list of pointers if you support multiple selection, to the selected items. Your OnDraw function must draw all OLE items.

  2. Override IsSelected to check whether the item passed to it is currently selected.

  3. Implement an OnInsertObject message handler to display the Insert Object dialog box.

  4. Implement an OnSetFocus message handler to transfer focus from the view to an in-place active OLE embedded item.

  5. Implement an OnSize message handler to inform an OLE embedded item that it needs to change its rectangle to reflect the change in size of its containing view.

Because the implementation of these features varies dramatically from one application to the next, AppWizard provides only a basic implementation. You will likely have to customize these functions to get your application to function properly. For a more detailed explanation and an example of this, see the "Refining Active Container Functionality" section of Creating an OLE Container in Tutorials, and see the MFC Tutorial sample CONTAINER.

To handle embedded and linked items

  1. Derive a class from COleClientItem. Objects of this class represent items that have been embedded in or linked to your OLE document.

  2. Override OnChange, OnChangeItemPosition, and OnGetItemPosition. These functions handle sizing, positioning, and modifying embedded and linked items.

AppWizard will derive the class for you, but you will likely need to override OnChange and the other functions listed with it in step 2 in the preceding procedure. The skeleton implementations need to be customized for most applications, because these functions are implemented differently from one application to the next. For more information about this, see step 2 of the container tutorial (called "Refining Active Container Functionality") in Tutorials and the MFC OLE sample DRAWCLI.

You must add a number of items to the container application’s menu structure to support OLE. For more information on these, see the article Menus and Resources: Container Additions.

You may also want to support some of the following features in your container application:

  • In-place activation when editing an embedded item.

    For more information, see the article Activation.

  • Creation of OLE items by dragging and dropping a selection from a server application.

    For more information, see the article Drag and Drop (OLE).

  • Links to embedded objects or combination container/server applications.

    For more information, see the article Containers: Advanced Features.

See Also Containers: Client Items


Containers: Client Items

Home | Overview | How Do I | Sample | Tutorial

This article explains what client items are and from what classes your application should derive its client items.

Client items are data items belonging to another application that are either contained in or referenced by an OLE container application’s document. Client items whose data is contained within the document are embedded; those whose data is stored in another location referenced by the container document are linked.

The document class in an OLE application is derived from the class COleDocument rather than CDocument. The COleDocument class inherits from CDocument all of the functionality necessary for using the document/view architecture on which MFC applications are based. COleDocument also defines an interface that treats a document as a collection of CDocItem objects. Several COleDocument member functions are provided for adding, retrieving, and deleting elements of that collection.

Every container application should derive at least one class from COleClientItem. Objects of this class represent items, embedded or linked, in the OLE document. These objects exist for the life of the document containing them, unless they are deleted from the document.

CDocItem is the base class for COleClientItem and COleServerItem. Objects of classes derived from these two act as intermediaries between the OLE item and the client and server applications, respectively. Each time a new OLE item is added to the document, the MFC framework adds a new object of your client application’s COleClientItem-derived class to the document’s collection of CDocItem objects.

See Also Containers: Compound Files, Containers: User-Interface Issues, Containers: Advanced Features, COleClientItem, COleServerItem


Containers: Client-Item Notifications

Home | Overview | How Do I | Sample | Tutorial

This article discusses the overridable functions that the MFC framework calls when server applications modify items in your client application’s document.

COleClientItem defines several overridable functions that are called in response to requests from the component application, which is also called the server application. These overridables usually act as notifications. They inform the container application of various events, such as scrolling, activation, or a change of position, and of changes that the user makes when editing or otherwise manipulating the item.

The framework notifies your container application of changes through a call to COleClientItem::OnChange, an overridable function whose implementation is required. This protected function receives two arguments. The first specifies the reason the server changed the item:

Notification | Meaning
OLE_CHANGED | The OLE item’s appearance has changed.
OLE_SAVED | The OLE item has been saved.
OLE_CLOSED | The OLE item has been closed.
OLE_RENAMED | The server document containing the OLE item has been renamed.
OLE_CHANGED_STATE | The OLE item has changed from one state to another.
OLE_CHANGED_ASPECT | The OLE item’s draw aspect has been changed by the framework.

These values are from the OLE_NOTIFICATION enumeration, which is defined in AFXOLE.H.

The second argument to this function specifies how the item has changed or what state it has entered:

When first argument is | Second argument
OLE_SAVED or OLE_CLOSED | Is not used.
OLE_CHANGED | Specifies the aspect of the OLE item that has changed.
OLE_CHANGED_STATE | Describes the state being entered (emptyState, loadedState, openState, activeState, or activeUIState).

For further information about the states a client item can assume, see the article Containers: Client-Item States.

The framework calls COleClientItem::OnGetItemPosition when an item is being activated for in-place editing. Implementation is required for applications that support in-place editing. AppWizard provides a basic implementation, which assigns the item’s coordinates to the CRect object that is passed as an argument to OnGetItemPosition.

If an OLE item’s position or size changes during in-place editing, the container’s information about the item’s position and clipping rectangles must be updated and the server must receive information about the changes. The framework calls COleClientItem::OnChangeItemPosition for this purpose. AppWizard provides an override that calls the base class’s function. You should edit the function AppWizard writes for your COleClientItem-derived class so that the function updates any information retained by your client-item object.

See Also Containers: Client-Item States, COleClientItem::OnChangeItemPosition


Containers: Client-Item States

Home | Overview | How Do I | Sample | Tutorial

This article explains the different states a client item passes through in its lifetime.

A client item passes through several states as it is created, activated, modified, and saved. Each time the item’s state changes, the framework calls COleClientItem::OnChange with the OLE_CHANGED_STATE notification. The second parameter is a value from the COleClientItem::ItemState enumeration. It can be one of the following:

  • COleClientItem::emptyState

  • COleClientItem::loadedState

  • COleClientItem::openState

  • COleClientItem::activeState

  • COleClientItem::activeUIState

In the empty state, a client item is not yet completely an item. Memory has been allocated for it, but it has not yet been initialized with the OLE item’s data. This is the state a client item is in when it has been created through a call to new but has not yet undergone the second step of the typical two-step creation.

In the second step, performed through a call to COleClientItem::CreateFromFile or another CreateFrom xxxx function, the item is completely created. The OLE data (from a file or some other source, such as the Clipboard) has been associated with the COleClientItem-derived object. Now the item is in the loaded state.

When an item has been opened in the server’s window rather than opened in place in the container’s document, it is in the open (or fully open) state. In this state, a cross-hatch usually is drawn over the representation of the item in the container’s window to indicate that the item is active elsewhere.

When an item has been activated in place, it passes, usually only briefly, through the active state. It then enters the UI active state, in which the server has merged its menus, toolbars, and other user-interface components with those of the container. The presence of these user-interface components distinguishes the UI active state from the active state. Otherwise, the active state resembles the UI active state. If the server supports Undo, the server is required to retain the OLE item’s undo-state information until it reaches the loaded or open state.

See Also Activation, Containers: Client-Item Notifications, Trackers, CRectTracker


Containers: Compound Files

Home | Overview | How Do I | Sample | Tutorial

This article explains the components and implementation of compound files and the advantages and disadvantages of using compound files in your OLE applications.

Compound files are an integral part of OLE. They are used to facilitate data transfer and OLE document storage. Compound files are an implementation of the Active structured storage model. Consistent interfaces exist that support serialization to a storage, a stream, or a file object. Compound files are supported in the Microsoft Foundation Class Library by the classes COleStreamFile and COleDocument.

Note Using a compound file does not imply that the information comes from an OLE document or a compound document. Compound files are just one of the ways to store compound documents, OLE documents, and other data.

Components of a Compound File

OLE’s implementation of compound files uses three object types: stream objects, storage objects, and ILockBytes objects. These objects are similar to the components of a standard file system in the following ways:

  • Stream objects, like files, store data of any type.

  • Storage objects, like directories, can contain other storage and stream objects.

  • LockBytes objects represent the interface between the storage objects and the physical hardware. They determine how the actual bytes are written to whatever storage device the LockBytes object is accessing, such as a hard drive or an area of global memory. For more information about LockBytes objects and the ILockBytes interface, see the OLE Programmer’s Reference.

Advantages and Disadvantages of Compound Files

Compound files provide benefits not available with earlier methods of file storage. They include:

  • Incremental file accessing

  • File access modes

  • Standardization of file structure

The potential disadvantages of compound files — large size and performance issues relating to storage on floppy disks — should be considered when deciding whether to use them in your application.

Incremental Access to Files

Incremental access to files is an automatic benefit of using compound files. Because a compound file can be viewed as a “file system within a file,” individual object types, such as stream or storage, can be accessed without the need to load the entire file. This can dramatically decrease the time an application needs to access new objects for editing by the user. Incremental updating, based on the same concept, offers similar benefits. Instead of saving the entire file just to save the changes made to one object, OLE saves only the stream or storage object edited by the user.

File Access Modes

Being able to determine when changes to objects in a compound file are committed to disk is another benefit of using compound files. The mode in which files are accessed, either transacted or direct, determines when changes are committed.

  • Transacted mode uses a two-phase commit operation to make changes to objects in a compound file, thereby keeping both the old and the new copies of the document available until the user chooses to either save or undo the changes.

  • Direct mode incorporates changes to the document as they are made, without the ability to later undo them.

For more information on access modes, see the OLE Programmer’s Reference.

Standardization

The standardized structure of compound files allows different OLE applications to browse through compound files created by your OLE application with no knowledge of the application that actually created the file.

Size and Performance Considerations

Because of the complexity of the compound file storage structure and the ability to save data incrementally, files using this format tend to be larger than other files using unstructured or “flat file” storage. If your application frequently loads and saves files, using compound files can cause the file size to increase much more quickly than noncompound files. Because compound files can get large, the access time for files stored on and loaded from floppy disks can also be affected, resulting in slower access to files.

Another issue that affects performance is compound-file fragmentation. The size of a compound file is determined by the difference between the first and last disk sectors used by the file. A fragmented file can contain many areas of free space that do not contain data, but are counted when calculating the size. During the lifetime of a compound file, these areas are created by the insertion or deletion of storage objects.

Using Compound Files Format for Your Data

After successfully creating an application that has a document class derived from COleDocument, ensure that your main document constructor calls EnableCompoundFile. When AppWizard creates OLE container applications, this call is inserted for you.

In the OLE Programmer’s Reference, see IStream, IStorage, ILockBytes.

See Also Containers: User-Interface Issues, COleStreamFile, COleDocument


Containers: User-Interface Issues

Home | Overview | How Do I | Sample | Tutorial

You must add a number of features to a container application’s user interface to adequately manage linked and embedded items. These features involve changes to the menu structure and to the events that the application handles. For detailed information about them, see the following articles:

For information on | See
Menu additions for containers | Menus and Resources: Container Additions
Additional resources for containers | Menus and Resources: Container Additions
Painting linked or embedded items | Tutorials, Container Tutorial
New dialog boxes for containers | Dialog Boxes in OLE

See Also Containers: Advanced Features, Menus and Resources (OLE)


Containers: Advanced Features

Home | Overview | How Do I | Sample | Tutorial

This article describes the steps necessary to incorporate optional advanced features into existing container applications. These features are:

  • An application that is both a container and a server

  • An OLE link to an embedded object

Creating a Container/Server Application

A container/server application is an application that acts as both a container and a server. Microsoft Word for Windows is an example of this. You can embed Word for Windows documents in other applications, and you can also embed items in Word for Windows documents. The process for modifying your container application to be both a container and a full-server (you can’t create a combination container/mini-server application) is similar to the process for creating a full-server.

The article Servers: Implementing a Server lists a number of tasks required to implement a server application. If you convert a container application to a container/server application, you’ll need to perform some of those same tasks, adding code to the container. The following lists the important things to consider:

  • The container code created by AppWizard already initializes the OLE subsystem. You won’t need to change or add anything for that support.

  • Wherever the base class of a document class is COleDocument, change the base class to COleServerDoc.

  • Override COleClientItem::CanActivate to avoid editing items in place while the server itself is being used to edit in place.

    For example: the MFC OLE sample OCLIENT has embedded an item created by your container/server application. You open the OCLIENT application and in-place edit the item created by your container/server application. While editing your application’s item, you decide you want to embed an item created by the MFC OLE sample HIERSVR. To do this, you cannot use in-place activation. You must fully open HIERSVR to activate this item. Because the Microsoft Foundation Class Library does not support this OLE feature, overriding COleClientItem::CanActivate allows you to check for this situation and prevent a possible run-time error in your application.

If you are creating a new application and want it to function as a container/server application, choose that option in the OLE Options dialog box in AppWizard and this support will be created automatically. For more information, see the article Overview: Creating an ActiveX Control Container. For information about MFC samples, see MFC Samples.

Note that you cannot insert an MDI application into itself. An application that is a container/server cannot be inserted into itself unless it is an SDI application.

Links to Embedded Objects

The Links to Embedded Objects feature enables a user to create a document with an OLE link to an embedded object inside your container application. For example, create a document in a word processor containing an embedded spreadsheet. If your application supports links to embedded objects, it could paste a link to the spreadsheet contained in the word processor’s document. This feature allows your application to use the information contained in the spreadsheet without knowing where the word processor originally got it.

To link to embedded objects in your application

  1. Derive your document class from COleLinkingDoc instead of COleDocument.

  2. Create an OLE class ID (CLSID) for your application by using the Class ID Generator included with the OLE Development Tools.

  3. Register the application with OLE.

  4. Create a COleTemplateServer object as a member of your application class.

  5. In your application class’s InitInstance member function, do the following:
    • Connect your COleTemplateServer object to your document templates by calling the object’s ConnectTemplate member function.

    • Call the COleTemplateServer::RegisterAll member function to register all class objects with the OLE system.

    • Call COleTemplateServer::UpdateRegistry. The only parameter to UpdateRegistry should be OAT_CONTAINER if the application is not launched with the “/Embedded” switch. This registers the application as a container that can support links to embedded objects.

      If the application is launched with the “/Embedded” switch, it should not show its main window, similar to a server application.

The MFC OLE sample OCLIENT implements this feature. For an example of how this is done, see the InitInstance function in the OCLIENT.CPP file of this sample application.

See Also Servers


Data Objects and Data Sources (OLE)

Home | Overview | How Do I | Sample | Tutorial

When you perform a data transfer, either by using the Clipboard or drag and drop, the data has a source and a destination. One application provides the data for copying and another application accepts it for pasting. Each side of the transfer needs to perform different operations on the same data for the transfer to succeed. The Microsoft Foundation Class Library (MFC) provides two classes that represent each side of this transfer:

  • Data sources (as implemented by COleDataSource objects) represent the source side of the data transfer. They are created by the source application when data is to be copied to the Clipboard, or when data is provided for a drag-and-drop operation.

  • Data objects (as implemented by COleDataObject objects) represent the destination side of the data transfer. They are created when the destination application has data dropped into it, or when it is asked to perform a paste operation from the Clipboard.

The following articles explain how to use data objects and data sources in your applications. This information applies to both container and server applications, because both may be called upon to copy and paste data.

  • Data Objects and Data Sources: Creation and Destruction

  • Data Objects and Data Sources: Manipulation

What do you want to know more about?

  • Drag and drop

  • Clipboard

See Also COleDataObject, COleDataSource


Data Objects and Data Sources: Creation and Destruction

Home | Overview | How Do I | Sample | Tutorial

As explained in the article Data Objects and Data Sources (OLE), data objects and data sources represent both sides of a data transfer. This article explains when to create and destroy these objects and sources to perform your data transfers properly. Topics include:

  • Creating data objects

  • Destroying data objects

  • Creating data sources

  • Destroying data sources

Creating Data Objects

Data objects are used by the destination application — either the client or the server. A data object in the destination application is one end of a connection between the source application and the destination application. A data object in the destination application is used to access and interact with the data in the data source.

There are two common situations where a data object is needed. The first is when data is dropped in your application using drag and drop. The second is when Paste or Paste Special is chosen from the Edit Menu.

In a drag-and-drop situation, you do not need to create a data object. A pointer to an existing data object will be passed to your OnDrop function. This data object is created by the framework as part of the drag-and-drop operation and will also be destroyed by it. This is not always the case when pasting is done by another method. For more information, see Destroying Data Objects.

If the application is performing a paste or paste special operation, you should create a COleDataObject object and call its AttachClipboard member function. This associates the data object with the data on the Clipboard. You can then use this data object in your paste function.

For an example of how this is done, see the DoPasteItem function in the MAINVIEW.CPP file that is part of the MFC OLE sample OCLIENT. OCLIENT implements a function that performs all paste operations and calls DoPasteItem from its OnDrop, OnPaste, and OnPasteLink functions. Because OnDrop has a pointer to a data object passed to it, it passes the pointer on to DoPasteItem. OnPaste and OnPasteLink pass NULL for this parameter, telling DoPasteItem to create a data object and attach it to the Clipboard. This scheme separates your paste code so you only have to debug it in one place, but you can still use it for both kinds of paste operations.

Destroying Data Objects

If you follow the scheme described in Creating Data Objects, destroying data objects is a trivial aspect of data transfers. The data object that was created in your paste function will be destroyed by MFC when your paste function returns.

If you follow another method of handling paste operations, make sure the data object is destroyed after your paste operation is complete. Until the data object is destroyed, it will be impossible for any application to successfully copy data to the Clipboard.

Creating Data Sources

Data sources are used by the source of the data transfer — which can be either the client or the server side of the data transfer. A data source in the source application is one end of a connection between the source application and the destination application. A data object in the destination application is used to interact with the data in the data source.

Data sources are created when an application needs to copy data to the Clipboard. A typical scenario runs like this:

  1. The user selects some data.

  2. The user chooses Copy (or Cut) from the Edit menu or begins a drag-and-drop operation.

  3. Depending on the design of the program, the application creates either a COleDataSource object or an object from a class derived from COleDataSource.

  4. The selected data is inserted into the data source by calling one of the functions in the COleDataSource::CacheData or COleDataSource::DelayRenderData groups.

  5. The application calls the SetClipboard member function (or the DoDragDrop member function if this is a drag-and-drop operation) belonging to the object created in step 3.

  6. If this is a Cut operation or DoDragDrop returns DROPEFFECT_MOVE, the data selected in step 1 is deleted from the document.

This scenario is implemented by the MFC OLE samples OCLIENT and HIERSVR. Look at the source for each application’s CView-derived class for all but the GetClipboardData and OnGetClipboardData functions. These two functions are in either the COleClientItem or COleServerItem-derived class implementations. These sample programs provide a good example of how to implement these concepts.

One other situation in which you might want to create a COleDataSource object occurs if you are modifying the default behavior of a drag-and-drop operation. For more information, see the Drag and Drop: Customizing article.

Destroying Data Sources

Data sources must be destroyed by the application currently responsible for them. In situations where you hand the data source to OLE, such as calling COleDataSource::SetClipboard, you do not have to worry about destroying it because it will be destroyed by OLE. If you do not hand your data source to OLE, then you are responsible for destroying it, as with any typical C++ object.

What do you want to know more about?

  • Drag and drop

  • Clipboard

  • Manipulating data objects and data sources

See Also COleDataObject, COleDataSource


Data Objects and Data Sources: Manipulation

Home | Overview | How Do I | Sample | Tutorial

After a data object or data source has been created, you can perform a number of common operations on the data, such as inserting and removing data, enumerating the formats the data is in, and more. This article describes the techniques necessary to complete the most common operations. Topics include:

  • Inserting data into a data source

  • Determining the formats available in a data object

  • Retrieving data from a data object

Inserting Data into a Data Source

How data is inserted into a data source depends on whether the data is supplied immediately or on demand, and in which medium it is supplied. The possibilities are as follows.

Supplying Data Immediately (Immediate Rendering)

  • Call COleDataSource::CacheGlobalData repeatedly for every Clipboard format in which you are supplying data. Pass the Clipboard format to be used, a handle to the memory containing the data and, optionally, a FORMATETC structure describing the data.

    -or-

  • If you want to work directly with STGMEDIUM structures, you call COleDataSource::CacheData instead of COleDataSource::CacheGlobalData in the option above.

Supplying Data on Demand (Delayed Rendering)

This is an advanced topic.

  • Call COleDataSource::DelayRenderData repeatedly for every Clipboard format in which you are supplying data. Pass the Clipboard format to be used and, optionally, a FORMATETC structure describing the data. When the data is requested, the framework will call COleDataSource::OnRenderData, which you must override.

    -or-

  • If you use a CFile object to supply the data, call COleDataSource::DelayRenderFileData instead of COleDataSource::DelayRenderData in the option above. When the data is requested, the framework will call COleDataSource::OnRenderFileData, which you must override.

Determining the Formats Available in a Data Object

Before an application allows the user to paste data into it, it needs to know if there are formats on the Clipboard that it can handle. To do this, your application should do the following:

  1. Create a COleDataObject object and a FORMATETC structure.

  2. Call the data object’s AttachClipboard member function to associate the data object with the data on the Clipboard.

  3. Do one of the following:
    • Call the data object’s IsDataAvailable member function if there are only one or two formats you need. This will save you time in cases where the data on the Clipboard supports significantly more formats than your application.

      -or-

    • Call the data object’s BeginEnumFormats member function to start enumerating the formats available on the Clipboard. Then call GetNextFormat until the Clipboard returns a format your application supports or there are no more formats.

If you are using ON_UPDATE_COMMAND_UI, you can now enable the Paste and, possibly, Paste Special items on the Edit menu. To do this, call either CMenu::EnableMenuItem or CCmdUI::Enable. For more information on what container applications should do with menu items and when, see the Menus and Resources: Container Additions article.

Retrieving Data from a Data Object

Once you have decided on a data format, all that’s left is to retrieve the data from the data object. To do this, the user decides where he or she wants to put the data, and the application calls the appropriate function. The data will be available in one of the following mediums:

Medium | Function to call
Global Memory (HGLOBAL) | COleDataObject::GetGlobalData
File (CFile) | COleDataObject::GetFileData
STGMEDIUM structure (IStorage) | COleDataObject::GetData

Commonly, the medium will be specified along with its Clipboard format. For example, a CF_EMBEDDEDSTRUCT object is always in an IStorage medium that requires an STGMEDIUM structure. Therefore, you would use GetData because it is the only one of these functions that can accept an STGMEDIUM structure.

For cases where the Clipboard format is in an IStream or HGLOBAL medium, the framework can provide a CFile pointer that references the data. The application can then use file read to get the data in much the same way as it might import data from a file. Essentially, this is the client-side interface to the OnRenderData and OnRenderFileData routines in the data source.

The user can now insert data into the document just like for any other data in the same format.

What do you want to know more about?

  • Drag and drop

  • Clipboard

See Also COleDataObject, COleDataSource


Drag and Drop (OLE)

Home | Overview | How Do I | Sample | Tutorial

The drag-and-drop feature of OLE is primarily a shortcut for copying and pasting data. When you use the Clipboard to copy or paste data, a number of steps are required. You select the data, choose Cut or Copy from the Edit menu, move to the destination file, window or application, place the cursor in the desired location, and choose Paste from the Edit menu.

OLE drag and drop is different from File Manager’s drag-and-drop mechanism, which can only handle filenames and is designed specifically to pass filenames to applications. OLE drag and drop is much more general. It allows you to drag and drop any data that could also be placed on the Clipboard.

When you use OLE drag and drop, you remove two steps from the process. You select the data from the source window (the “drop source”), drag it to the desired destination (the “drop target”), and drop it by releasing the mouse button. The operation eliminates the need for menus and is quicker than the copy/paste sequence. The only requirement is that both the drop source and drop target must be open and at least partially visible on the screen.

Using OLE drag and drop, data can be transferred from one location to another within a document, between different documents, or between applications. It can be implemented in either a container or a server application, and any application can be a drop source, a drop target, or both. If an application has both drop-source and drop-target support implemented, drag and drop is enabled between child windows, or within one window. This feature can make your application much easier to use.

If you only want to use the drag-and-drop capabilities of OLE, see the article Drag and Drop: Customizing. You can use the techniques explained in that article to make non-OLE applications drop sources. The article Drag and Drop: Implementing a Drop Target describes how to implement drop-target support for both OLE and non-OLE applications. It will also be helpful to examine the MFC OLE samples OCLIENT and HIERSVR.

If you have not read the Data Objects and Data Sources (OLE) family of articles, you may want to do so now. These articles explain the fundamentals of data transfer, and how to implement it in your applications.

For more information about drag and drop, see the following articles:

  • Drag and Drop: Implementing a Drop Source

  • Drag and Drop: Implementing a Drop Target

  • Drag and Drop: Customizing

See Also Data Objects and Data Sources (OLE)


Drag and Drop: Implementing a Drop Source

Home | Overview | How Do I | Sample | Tutorial

This article explains how to get your application to provide data to a drag-and-drop operation.

Basic implementation of a drop source is relatively simple. The first step is to determine what events begin a drag operation. Recommended user interface guidelines define the beginning of a drag operation as the selection of data and a WM_LBUTTONDOWN event occurring on a point inside the selected data. The MFC OLE samples OCLIENT and HIERSVR follow these guidelines.

If your application is a container and the selected data is a linked or an embedded object of type COleClientItem, call its DoDragDrop member function. Otherwise, construct a COleDataSource object, initialize it with the selection, and call the data source object’s DoDragDrop member function. If your application is a server, use COleServerItem::DoDragDrop. For information about customizing standard drag-and-drop behavior, see the article Drag and Drop: Customizing.

If DoDragDrop returns DROPEFFECT_MOVE, delete the source data from the source document immediately. No other return value from DoDragDrop has any effect on a drop source.

What do you want to know more about?

  • Implementing a drop target

  • Customizing drag and drop

  • Creating and destroying OLE data objects and data sources

  • Manipulating OLE data objects and data sources

See Also COleDataSource::DoDragDrop, COleClientItem::DoDragDrop, CView::OnDragLeave


Drag and Drop: Implementing a Drop Target

Home | Overview | How Do I | Sample | Tutorial

This article outlines how to make your application a drop target. Implementing a drop target takes slightly more work than implementing a drop source, but it’s still relatively simple. These techniques also apply to non-OLE applications.

To implement a drop target

  1. Add a member variable to each view in the application that you want to be a drop target. This member variable must be of type COleDropTarget or a class derived from it.

  2. From your view class’s function that handles the WM_CREATE message (typically OnCreate), call the new member variable’s Register member function. Revoke will be called automatically for you when your view is destroyed.

  3. Override the following functions. If you want the same behavior throughout your application, override these functions in your view class. If you want to modify behavior in isolated cases or want to enable dropping on non-CView windows, override these functions in your COleDropTarget-derived class.
    Override | To allow
    OnDragEnter | Drop operations to occur in the window. Called when the cursor first enters the window.
    OnDragLeave | Special behavior when the drag operation leaves the specified window.
    OnDragOver | Drop operations to occur in the window. Called when the cursor is being dragged across the window.
    OnDrop | Handling of data being dropped into the specified window.
    OnScrollBy | Special behavior for when scrolling is necessary in the target window.

See the MAINVIEW.CPP file that is part of the MFC OLE sample OCLIENT for an example of how these functions work together.

What do you want to know more about?

  • Implementing a drop source

  • Creating and destroying OLE data objects and data sources

  • Manipulating OLE data objects and data sources

See Also COleDropTarget


Drag and Drop: Customizing

Home | Overview | How Do I | Sample | Tutorial

The default implementation of the drag-and-drop feature is sufficient for most applications. However, some applications may require that this standard behavior be changed. This article explains the steps necessary to change these defaults. In addition, you can use this technique to establish applications that do not support compound documents as drop sources.

If you are customizing standard OLE drag-and-drop behavior, or you have a non-OLE application, you must create a COleDataSource object to contain the data. When the user starts a drag-and-drop operation, your code should call the DoDragDrop function from this object instead of from other classes that support drag-and-drop operations.

Optionally, you can create a COleDropSource object to control the drop and override some of its functions depending on the type of behavior you want to change. This drop-source object is then passed to COleDataSource::DoDragDrop to change the default behavior of these functions. These different options allow a great deal of flexibility in how you support drag-and-drop operations in your application. For more information about data sources, see the article Data Objects and Data Sources (OLE).

You can override the following functions to customize drag-and-drop operations:

Override | To customize
OnBeginDrag | How dragging is initiated after you call DoDragDrop.
GiveFeedback | Visual feedback, such as cursor appearance, for different drop results.
QueryContinueDrag | The termination of a drag-and-drop operation. This function enables you to check modifier key states during the drag operation.

See Also COleDropSource, COleDataSource


Menus and Resources (OLE)

Home | Overview | How Do I | Sample | Tutorial

This group of articles explains the use of menus and resources in MFC OLE document applications.

OLE visual editing places additional requirements on the menu and other resources provided by OLE document applications because there are a number of modes in which both container and server (component) applications can be started and used. For example, a full-server application can run in any of these three modes:

  • Stand-alone

  • In place, for editing an item within the context of a container

  • Open, for editing an item outside the context of its container, often in a separate window

This requires three separate menu layouts, one for each possible mode of the application. Accelerator tables are also necessary for each new mode. A container application may or may not support in-place activation; if it does, it needs a new menu structure and associated accelerator tables.

In-place activation requires that the container and server applications must negotiate for menu, toolbar, and status bar space. All resources must be designed with this in mind. The article Menus and Resources: Menu Merging covers this topic in detail.

Because of these issues, OLE document applications created with AppWizard can have up to four separate menus and accelerator table resources. These are used for the following reasons:

Resource name | Use
IDR_MAINFRAME | Used in an MDI application if no file is open, or in an SDI application regardless of open files. This is the standard menu used in non-OLE applications.
IDR_<project>TYPE | Used in an MDI application if files are open. Used when an application is running stand-alone. This is the standard menu used in non-OLE applications.
IDR_<project>TYPE_SRVR_IP | Used by the server or container when an object is open in place.
IDR_<project>TYPE_SRVR_EMB | Used by a server application if an object is opened without using in-place activation.

Each of these resource names represents a menu and, usually, an accelerator table. A similar scheme should be used in MFC applications that are not created with AppWizard.

The following articles discuss topics related to containers, servers, and the menu merging necessary to implement in-place activation:

  • Menus and Resources: Container Additions

  • Menus and Resources: Server Additions

  • Menus and Resources: Menu Merging


Menus and Resources: Container Additions

Home | Overview | How Do I | Sample | Tutorial

This article explains the changes that need to be made to the menus and other resources in a visual editing container application.

In container applications, two types of changes need to be made: modifications to existing resources to support OLE visual editing and addition of new resources used for in-place activation. If you use AppWizard to create your container application, these steps will be done for you, but they may require some customization.

If you don’t use AppWizard, you may want to look at OCLIENT.RC, the resource script for the OCLIENT sample application, to see how these changes are implemented. See the MFC OLE sample OCLIENT.

Topics covered in this article include:

  • Container menu additions

  • Accelerator table additions

  • String table additions

Container Menu Additions

You must add the following items to the Edit menu:

Item | Purpose
Insert New Object... | Opens the OLE Insert Object dialog box to insert a linked or embedded item into the document.
Paste Link | Pastes a link to the item on the Clipboard into the document.
OLE Verb | Calls the selected item’s primary verb. The text of this menu item changes to reflect the primary verb of the selected item.
Links... | Opens the OLE Edit Links dialog box to change existing linked items.

In addition to the changes listed in this article, your source file must include AFXOLECL.RC, which is required for the Microsoft Foundation Class Library implementation. Insert New Object is the only required menu addition. Other items can be added, but those listed here are the most common.

You must create a new menu for your container application if you want to support in-place activation of contained items. This menu consists of the same File menu and Window pop-up menus used when files are open, but it has two separators placed between them. These separators are used to indicate where the server (component) item (application) should place its menus when activated in place. For more information on this menu-merging technique, see the article Menus and Resources: Menu Merging.

Container Application Accelerator Table Additions

Small changes to a container application’s accelerator table resources are necessary if you are supporting in-place activation. The first change allows the user to press the escape key (ESC) to cancel the in-place editing mode. Add the following entry to the main accelerator table:

ID | Key | Type
ID_CANCEL_EDIT_CNTR | VK_ESCAPE | VIRTKEY

The second change is to create a new accelerator table that corresponds to the new menu resource created for in-place activation. This table has entries for the File and Window menus in addition to the VK_ESCAPE entry above. The following example is the accelerator table created for in-place activation in the MFC tutorial CONTAINER:

ID | Key | Type
ID_FILE_NEW | CTRL + N | VIRTKEY
ID_FILE_OPEN | CTRL + O | VIRTKEY
ID_FILE_SAVE | CTRL + S | VIRTKEY
ID_FILE_PRINT | CTRL + P | VIRTKEY
ID_NEXT_PANE | VK_F6 | VIRTKEY
ID_PREV_PANE | SHIFT + VK_F6 | VIRTKEY
ID_CANCEL_EDIT_CNTR | VK_ESCAPE | VIRTKEY

String Table Additions for Container Applications

Most of the changes to string tables for container applications correspond to the additional menu items mentioned in Container Menu Additions. They supply the text displayed in the status bar when each menu item is displayed. As an example, here are the string-table entries AppWizard generates:

ID | String
IDP_OLE_INIT_FAILED | OLE initialization failed. Make sure that the OLE libraries are the correct version.
IDP_FAILED_TO_CREATE | Failed to create object. Make sure that the object is entered in the system registry.

See Also Menus and Resources: Server Additions


Menus and Resources: Server Additions

Home | Overview | How Do I | Sample | Tutorial

This article explains the changes that need to be made to the menus and other resources in a visual editing server (component) application. A server application requires many additions to the menu structure and other resources because it can be started in one of three modes: stand-alone, embedded, or in place. As described in the Menus and Resources (OLE) article, there are a maximum of four sets of menus. All four are used for an MDI full-server application, while only three are used for a mini-server. AppWizard will create the menu layout necessary for the type of server you want. Some customization may be necessary.

If you don’t use AppWizard, you may want to look at HIERSVR.RC, the resource script for the MFC sample application HIERSVR, to see how these changes are implemented.

Topics covered in this article include:

  • Server menu additions

  • Accelerator table additions

  • String table additions

  • Mini-Server additions

Server Menu Additions

Server (component) applications must have menu resources added to support OLE visual editing. The menus used when the application is run in stand-alone mode do not have to be changed, but you must add two new menu resources before building the application; one to support in-place activation and one to support the server being fully open. Both menu resources are used by full- and mini-server applications.

  • To support in-place activation, you must create a menu resource that is very similar to the menu resource used when run in stand-alone mode. The difference in this menu is that the File and Window items (and any other menu items that deal with the application, and not the data) are missing. The container application will supply these menu items. For more information on, and an example of, this menu-merging technique, see the article Menus and Resources: Menu Merging.

  • To support fully open activation, you must create a menu resource nearly identical to the menu resource used when run in stand-alone mode. The only modification to this menu resource is that some items are reworded to reflect the fact that the server is operating on an item embedded in a compound document. For example, in Step 7 of the Scribble tutorial, Creating an OLE Server, when the application is open in-place, the Save command on the File menu changes to Save Copy As.

In addition to the changes listed in this article, your resource file needs to include AFXOLESV.RC, which is required for the Microsoft Foundation Class Library implementation. This file is in the MFC\Include subdirectory.

Server Application Accelerator Table Additions

Two new accelerator table resources must be added to server applications; they correspond directly to the new menu resources described above. The first accelerator table is used when the server application is activated in place. It consists of all the entries in the view’s accelerator table except those tied to the File and Window menus.

The second table is nearly an exact copy of the view’s accelerator table. Any differences parallel changes made in the fully open menu mentioned in Server Menu Additions.

For an example of these accelerator table changes, compare the IDR_HIERSVRTYPE_SRVR_IP and IDR_HIERSVRTYPE_SRVR_EMB accelerator tables with IDR_MAINFRAME in the HIERSVR.RC file included in the MFC OLE sample HIERSVR. The File and Window accelerators are missing from the in-place table and exact copies of them are in the embedded table.

String Table Additions for Server Applications

Only one string table addition is necessary in a server application — a string to signify that the OLE initialization failed. As an example, here is the string-table entry AppWizard generates:

ID | String
IDP_OLE_INIT_FAILED | OLE initialization failed. Make sure that the OLE libraries are the correct version.

Mini-Server Additions

The same additions apply for mini-servers as those listed above for full-servers. Because a mini-server can’t be run in stand-alone mode, its main menu is much smaller. The main menu created by AppWizard has only a File menu, containing only the items Exit and About. Embedded and in-place menus and accelerators for mini-servers are exactly the same as those for full-servers.

See Also Menus and Resources: Menu Merging


Menus and Resources: Menu Merging

Home | Overview | How Do I | Sample | Tutorial

This article details the steps necessary for OLE document applications to handle visual editing and in-place activation properly. In-place activation poses a challenge for both container and server (component) applications. The user remains in the same frame window (within the context of the container document), but is actually running another application, the server. This requires coordination between the resources of the container and server applications.

Topics covered in this article include:

  • Menu layouts

  • Toolbars and status bars

Menu Layouts

The first step is to coordinate menu layouts.

For more information, see Menu Creation in the Win32 SDK.

Container applications should create a new menu to be used only when embedded items are activated in place. At the minimum, this menu should consist of the following, in the order listed:

  1. File menu identical to the one used when files are open. (Usually no other menu items are placed before the next item.)

  2. Two consecutive separators.

  3. Window menu identical to the one used when files are open (only if the container application in an MDI application). Some applications may have other menus, such as an Options menu, that belong in this group, which remains on the menu when an embedded item is activated in place.

Note There may be other menus that affect the view of the container document, such as Zoom. These container menus appear between the two separators in this menu resource.

Server (component) applications should also create a new menu specifically for in-place activation. It should be like the menu used when files are open, but without menu items, such as File and Window that manipulate the server document instead of the data. Typically, this menu consists of the following:

  1. Edit menu identical to the one used when files are open.

  2. Separator.

  3. Object editing menus, such as the Pen menu in the Scribble tutorial application.

  4. Separator.

  5. Help menu.

For an example, look at the layout of some sample in-place menus for a container and a server. The details of each menu item have been removed to make the example clearer. The container’s in-place menu has the following entries:

IDR_CONTAINERTYPE_CNTR_IP MENU PRELOAD DISCARDABLE
BEGIN
    POPUP "&File C1"
    MENUITEM SEPARATOR
    POPUP "&Zoom C2"
    MENUITEM SEPARATOR
    POPUP "&Options C3"
    POPUP "&Window C3"
END

The consecutive separators indicate where the first part of the server’s menu should go. Now look at the server’s in-place menu:

IDR_SERVERTYPE_SRVR_IP MENU PRELOAD DISCARDABLE
BEGIN
    POPUP "&Edit S1"
    MENUITEM SEPARATOR
    POPUP "&Format S2"
    MENUITEM SEPARATOR
    POPUP "&Help S3"
END

The separators here indicate where the second group of container menu items should go. The resulting menu structure when an object from this server is activated in place inside this container looks like this:

BEGIN
    POPUP "&File C1"
    POPUP "&Edit S1"
    POPUP "&Zoom C2"
    POPUP "&Format S2"
    POPUP "&Options C3
    POPUP "&Window C3"
    POPUP "&Help S3"
END

As you can see, the separators have been replaced with the different groups of each application’s menu.

Accelerator tables associated with the in-place menu should also be supplied by the server application. The container will incorporate them into its own accelerator tables.

When an embedded item is activated in place, the framework loads the in-place menu. It then asks the server application for its menu for in-place activation and inserts it where the separators are. This is how the menus combine. You get menus from the container for operating on the file and window placement, and you get menus from the server for operating on the item.

Toolbars and Status Bars

Server applications should create a new toolbar and store its bitmap in a separate file. AppWizard-generated applications store this bitmap in a file called ITOOLBAR.BMP. The new toolbar replaces the container application’s toolbar when your server’s item is activated in place, and should contain the same items as your normal toolbar, but remove icons representing items on the File and Window menus.

This toolbar is loaded in your COleIPFrameWnd-derived class, created for you by AppWizard. The status bar is handled by the container application. For more information on the implementation of in-place frame windows, see the article Servers: Implementing a Server.

See Also Activation, Servers, Containers


Registration

Home | Overview | How Do I | Sample | Tutorial

When a user wants to insert an OLE item into an application, OLE presents a list of object types to choose from. OLE gets this list from the system registration database, which contains information provided by all server applications. When a server registers itself, the entries it puts into the system registration database (the Registry) describe each type of object it supplies, file extensions, and the path to itself, among other information.

The framework and the OLE system DLLs use this registry to determine what types of OLE items are available on the system. The OLE system DLLs also use this registry to determine how to launch a server application when a linked or embedded object is activated.

This article describes what each server application needs to do when it is installed and each time it is executed.

For detailed information about the system registration database and the format of the .REG files used to update it, see the OLE Programmer’s Reference.

Server Installation

When you first install your server application, it should register all the types of OLE items that it supports. You can also have the server update the system registration database every time it executes as a stand-alone application. This keeps the registration database up-to-date if the server’s executable file is moved.

Note MFC applications generated by AppWizard automatically register themselves when they are run as stand-alone applications.

If you want to register your application during installation, use the RegEdit.Exe program. (In Windows 95, RegEdit is in the Windows directory. In Windows NT, it is in the Windows System32 directory.) If you include a setup program with your application, have the setup program run “RegEdit /S appname.reg”. (The /S flag indicates "silent" operation; that is, it does not display the dialog box reporting successful completion of the command.) Otherwise, instruct the user to run RegEdit manually.

Important The .Reg file created by AppWizard does not include the complete path for the executable. Your installation program must either modify the .Reg file to include the complete path to the executable or modify the PATH environment variable to include the installation directory.

RegEdit merges the contents of the .Reg text file into the registration database. To verify the database or to repair it, use the registry editor. Take care to avoid deleting essential OLE entries. (In Windows 95, the registry editor is RegEdit.Exe. In Windows NT, it is RegEdit32.Exe.)

Server Initialization

When you create a server application with AppWizard, the wizard completes all initialization tasks for you automatically. This section describes what you must do if you write a server application manually.

When a server application is launched by a container application, the OLE system DLLs add the “/Embedding” option to the server’s command line. A server application’s behavior differs depending on whether it was launched by a container, so the first thing an application should do when it begins execution is check for the “/Embedding” or “-Embedding” option on the command line. If this switch exists, load a different set of resources that show the server as being either in-place active or fully open. For more information, see the article Menus and Resources: Server Additions.

Your server application should also call its CWinApp::RunEmbedded function to parse the command line. If it returns a nonzero value, the application should not show its window because it has been run from a container application, not as a stand-alone application. This function updates the server’s entry in the system registration database and calls the RegisterAll member function for you, performing instance registration.

When your server application is starting, you must ensure that it can perform instance registration. Instance registration informs the OLE system DLLs that the server is active and ready to receive requests from containers. It does not add an entry to the registration database. Perform instance registration of the server by calling the ConnectTemplate member function defined by COleTemplateServer. This connects the CDocTemplate object to the COleTemplateServer object.

The ConnectTemplate function takes three parameters: the server’s CLSID, a pointer to the CDocTemplate object, and a flag indicating whether the server supports multiple instances. A mini-server must be able to support multiple instances; that is, it must be possible for multiple instances of the server to run simultaneously, one for each container. Consequently, pass TRUE for this flag when launching a mini-server.

If you are writing a mini-server, by definition it will always be launched by a container. You should still parse the command line to check for the “/Embedding” option. The absence of this option on the command line means that the user has tried to launch the mini-server as a stand-alone application. If this occurs, register the server with the system registration database and then display a message box informing the user to launch the mini-server from a container application.

See Also Servers, CWinApp::RunAutomated,CWinApp::RunEmbedded, COleTemplateServer


Servers

Home | Overview | How Do I | Sample | Tutorial

A server application (or component application) creates OLE items (or components) for use by container applications. A visual editing server application also supports visual editing or in-place activation. Another form of OLE server is an automation server. Some server applications support only the creation of embedded items; others support the creation of both embedded and linked items. Some support linking only, although this is rare. All server applications must support activation by container applications when the user wants to edit an item. An application can be both a container and a server. In other words, it can both incorporate data into its documents, and create data that can be incorporated as items into other applications’ documents.

A mini-server is a special type of server application that can only be launched by a container. Microsoft Draw and Microsoft Graph are examples of mini-servers. A mini-server does not store documents as files on disk. Instead, it reads its documents from and writes them to items in documents belonging to containers. As a result, a mini-server supports embedding only, not linking.

A full-server can be run either as a stand-alone application or launched by a container application. A full-server can store documents as files on disk. It can support embedding only, both embedding and linking, or linking only. The user of a container application can create an embedded item by choosing the Cut or Copy command in the server and the Paste command in the container. A linked item is created by choosing the Copy command in the server and the Paste Link command in the container. Alternatively, the user can create an embedded or linked item using the Insert Object dialog box.

The following table summarizes characteristics of different types of servers:

Server Characteristics

Type of server | Supports multiple instances | Items per document | Documents per instance
Mini-server | Yes | 1 | 1
SDI full-server | Yes | 1 (if linking is supported, 1 or more) | 1
MDI full-server | No (not required) | 1 (if linking is supported, 1 or more) | 0 or more

A server application should support multiple containers simultaneously, in the event that more than one container will be used to edit an embedded or linked item. If the server is an SDI application (or a mini-server with a dialog box interface), multiple instances of the server must be able to run simultaneously. This allows a separate instance of the application to handle each container request.

If the server is an MDI application, it can simply create a new MDI child window each time a container needs to edit an item. In this way, a single instance of the application can support multiple containers.

Your server application must tell the OLE system DLLs what to do if one instance of the server is already running when another container requests its services: whether it should launch a new instance of the server or direct all containers’ requests to one instance of the server.

For more details on servers, see the following articles:

  • Servers: Implementing a Server

  • Servers: Implementing Server Documents

  • Servers: Implementing In-Place Frame Windows

  • Servers: Server Items

  • Servers: User-Interface Issues

See Also Containers, Containers: Advanced Features, Menus and Resources (OLE), Registration, Automation Servers


Servers: Implementing a Server

Home | Overview | How Do I | Sample | Tutorial

This article explains the code AppWizard creates for a visual editing server application. If you are not using AppWizard, this article lists the areas where you must write code to implement a server application.

If you are using AppWizard to create a new server application, AppWizard provides a significant amount of server-specific code for you. If you are adding visual editing server functionality to an existing application, you must duplicate the code that AppWizard would have provided before adding the rest of the necessary server code.

The server code that AppWizard provides falls into several categories:

  • Defining server resources:
    • The menu resource used when the server is editing an embedded item in its own window.

    • The menu and toolbar resources used when the server is active in place.

    For more information on these resources, see the article Menus and Resources: Server Additions.

  • Defining an item class derived from COleServerItem. For further details on server items, see the article Servers: Server Items.

  • Changing the base class of the document class to COleServerDoc. For further details, see the article Servers: Implementing Server Documents.

  • Defining a frame-window class derived from COleIPFrameWnd. For further details, see the article Servers: Implementing In-Place Frame Windows.

  • Creating an entry for the server application in the Windows registration database and registering the new instance of the server with the OLE system. For information on this topic, see the article Registration.

  • Initializing and launching the server application. For information on this topic, see the article Registration.

For more information, see COleServerItem, COleServerDoc, and COleIPFrameWnd in the Class Library Reference.

See Also Containers, Menus and Resources (OLE), Registration


Servers: Implementing Server Documents

Home | Overview | How Do I | Sample | Tutorial

This article explains the steps you must take to successfully implement a server document if you did not specify the OLE Server option in AppWizard.

To define a server document class

  1. Derive your document class from COleServerDoc instead of CDocument.

  2. Create a server item class derived from COleServerItem.

  3. Implement the OnGetEmbeddedItem member function of your server document class.

    OnGetEmbeddedItem is called when the user of a container application creates or edits an embedded item. It should return an item representing the entire document. This should be an object of your COleServerItem-derived class.

  4. Override the Serialize member function to serialize the contents of the document. You do not need to serialize the list of server items unless you are using them to represent the native data in your document. For more information, see Implementing Server Items in the article Servers: Server Items.

When a server document is created, the framework automatically registers the document with the OLE system DLLs. This allows the DLLs to identify the server documents.

For more information, see COleServerItem and COleServerDoc in the Class Library Reference.

See Also Servers: Server Items, Servers: Implementing a Server, Servers: Implementing In-Place Frame Windows


Servers: Implementing In-Place Frame Windows

Home | Overview | How Do I | Sample | Tutorial

This article explains what you must do to implement in-place frame windows in your visual editing server application if you do not use AppWizard to create your server application. In place of following the procedure outlined in this article, you could use an existing in-place frame-window class from either an AppWizard-generated application or a sample provided with Visual C++.

To declare an in-place frame-window class

  1. Derive an in-place frame-window class from COleIPFrameWnd.
    • Use the DECLARE_DYNCREATE macro in your class header file.

    • Use the IMPLEMENT_DYNCREATE macro in your class implementation (.CPP) file. This allows objects of this class to be created by the framework.
  2. Declare a COleResizeBar member in the frame-window class. This is needed if you want to support in-place resizing in server applications.

    Declare an OnCreate message handler (using ClassWizard), Call Create for your COleResizeBar member, if you’ve defined it.

  3. If you have a toolbar, declare a CToolBar member in the frame-window class.

    Override the OnCreateControlBars member function to create a toolbar when the server is active in place. For example:

    BOOL CInPlaceFrame::OnCreateControlBars
   (CWnd* pWndFrame, CWnd* pWndDoc)
{
   // create toolbar on client's frame window
   if (!m_wndToolBar.Create(pWndFrame) ||
       !m_wndToolBar.LoadToolBar(IDR_PROJ_SRVR_IP))
   {
      TRACE("Failed to create toolbar\n");
      return FALSE;
   }

   // set this window as owner, so messages are
   // delivered to proper app
   m_wndToolBar.SetOwner(this);

   // enable docking for the toolbar
   m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
   pWndFrame->EnableDocking(CBRS_ALIGN_ANY);
   pWndFrame->DockControlBar(&m_wndToolBar);

   // enable tooltips for the toolbar
   m_wndToolBar.SetBarStyle(CBRS_TOOLTIPS |
      CBRS_FLYBY | m_wndToolBar.GetBarStyle());

    return TRUE;
}

    See the discussion of this code following step 5.

  4. Include the header file for this in-place frame-window class in your main .CPP file.

  5. In InitInstance for your application class, call the SetServerInfo function of the document template object to specify the resources and in-place frame window to be used in open and in-place editing.

The series of function calls in the if statement creates the toolbar from the resources the server provided. At this point, the toolbar is part of the container’s window hierarchy. Because this toolbar is derived from CToolBar, it will pass its messages to its owner, the container application’s frame window, unless you change the owner. That is why the call to SetOwner is necessary. This call changes the window where commands are sent to be the server’s in-place frame window, causing the messages to be passed to the server. This allows the server to react to operations on the toolbar that it provides.

The ID for the toolbar bitmap should be the same as the other in-place resources defined in your server application. See the article Menus and Resources: Server Additions for details.

For more information, see COleIPFrameWnd, COleResizeBar, and CDocTemplate::SetServerInfo in the Class Library Reference.

See Also Servers: Implementing a Server, Servers: Implementing Server Documents, Servers: Server Items


Servers: Server Items

Home | Overview | How Do I | Sample | Tutorial

When a container launches a server so that a user can edit an embedded or linked OLE item, the server application creates a “server item.” The server item, which is an object of a class derived from COleServerItem, provides an interface between the server document and the container application.

The COleServerItem class defines several overridable member functions that are called by OLE, usually in response to requests from the container. Server items can represent part of the server document or the entire document. When an OLE item is embedded in the container document, the server item represents the entire server document. When the OLE item is linked, the server item can represent a part of the server document or the whole document, depending on whether the link is to a part or to the whole.

In the HIERSVR sample, for example, the server-item class, CServerItem, has a member that is a pointer to an object of the class CServerNode. The CServerNode object is a node in the HIERSVR application’s document, which is a tree. When the CServerNode object is the root node, the CServerItem object represents the whole document. When the CServerNode object is a child node, the CServerItem object represents a part of the document. See the MFC OLE sample HIERSVR for an example of this interaction.

Implementing Server Items

If you use AppWizard to produce “starter” code for your application, all you have to do to include server items in your starter code is to choose one of the server options from the OLE Options page. If you’re adding server items to an existing application, perform the following steps:

To implement a server item

  1. Derive a class from COleServerItem.

  2. In your derived class, override the OnDraw member function.

    The framework calls OnDraw to render the OLE item into a metafile. The container application uses this metafile to render the item. Your application’s view class also has an OnDraw member function, which is used to render the item when the server application is active.

  3. Implement an override of OnGetEmbeddedItem for your server-document class. For further information, see the article Servers: Implementing Server Documents and the MFC OLE sample HIERSVR.

  4. Implement your server-item class’s OnGetExtent member function. The framework calls this function to retrieve the size of the item. The default implementation does nothing.

A Tip for Server-Item Architecture

As noted in Implementing Server Items, server applications must be able to render items both in the server’s view and in a metafile used by the container application. In the Microsoft Foundation Class Library’s application architecture, the view class’s OnDraw member function renders the item when it is being edited (see CView::OnDraw in the Class Library Reference). The server item’s OnDraw renders the item into a metafile in all other cases (see COleServerItem::OnDraw).

You can avoid duplication of code by writing helper functions in your server-document class and calling them from the OnDraw functions in your view and server-item classes. The MFC OLE sample HIERSVR uses this strategy: the functions CServerView::OnDraw and CServerItem::OnDraw both call CServerDoc::DrawTree to render the item.

The view and the item both have OnDraw member functions because they draw under different conditions. The view must take into account such factors as zooming, selection size and extent, clipping, and user-interface elements such as scroll bars. The server item, on the other hand, always draws the entire OLE object.

For more information, see CView::OnDraw, COleServerItem, COleServerItem::OnDraw, and COleServerDoc::OnGetEmbeddedItem in the Class Library Reference.


Servers: User-Interface Issues

Home | Overview | How Do I | Sample | Tutorial

A server application has a number of features that must be added to the user interface to supply OLE items to container applications. For further information on the menus and additional resources that need to be added to a server application, see the article Menus and Resources: Server Additions.

See Also Menus and Resources (OLE)


Trackers

Home | Overview | How Do I | Sample | Tutorial

The CRectTracker class provides a user interface between rectangular items in your application and your user by providing a variety of display styles. These styles include: solid, hatched, or dashed borders; a hatched pattern that covers the item; and resize handles that can be located on the outside or inside of a border. Trackers are often used in conjunction with OLE items, that is, objects derived from COleClientItem. The tracker rectangles give visual cues on the current status of the item.

The MFC OLE sample OCLIENT demonstrates a common interface using trackers and OLE client items from the viewpoint of a container application. For a demonstration of the different styles and abilities of a tracker object, see the MFC general sample TRACKER.

For more information on implementing trackers in your OLE application, see the following article:

  • Trackers: Implementing Trackers in Your OLE Application

See Also COleClientItem


Trackers: Implementing Trackers in Your OLE Application

Home | Overview | How Do I | Sample | Tutorial

Trackers provide a graphical interface to enable users to interact with OLE client items. By using different tracker styles, OLE client items can be displayed with hatched borders, resize handles, or a variety of other visual effects. This article describes:

  • Tracking and how to implement it in your code.

  • The rubber-band effect and trackers.

The article also covers the use of styles with trackers.

In addition, it makes several references to the MFC OLE sample OCLIENT.

How to Implement Tracking in Your Code

Home | Overview | How Do I | Sample | Tutorial

To track an OLE item, you must handle certain events related to the item, such as clicking the item or updating the view of the document. In all cases, it is sufficient to declare a temporary CRectTracker object and manipulate the item by means of this object.

When a user selects an item or inserts an object with a menu command, you must initialize the tracker with the proper styles to represent the state of the OLE item. The following table outlines the conventions used by the OCLIENT sample. For more information on these styles, see CRectTracker.

Container Styles and States of the OLE Item

Style displayed | State of OLE item
Dotted border | Item is linked
Solid border | Item is embedded in your document
Resize handles | Item is currently selected
Hatched border | Item is currently in-place active
Hatching pattern overlays item | Item’s server is open

You can handle this initialization easily using a procedure that checks the state of the OLE item and sets the appropriate styles. The SetupTracker function found in the OCLIENT sample demonstrates tracker initialization. The parameters for this function are the address of the tracker, pTracker; a pointer to the client item that is related to the tracker, pItem; and a pointer to a rectangle, pTrueRect. For a more complete example of this function, see the MFC OLE sample OCLIENT.

The SetupTracker code example below presents a single function; lines of the function are interspersed with discussion of the function’s features:

void CMainView::SetupTracker( CRectTracker* pTracker,
  CRectItem* pItem, CRect* pTrueRect )
{

The tracker is initialized by setting the minimum size and clearing the style of the tracker.

  pTracker->m_sizeMin.cx = 8;
  pTracker->m_sizeMin.cy = 8;

  pTracker->m_nStyle = 0;

The following lines check to see whether the item is currently selected and whether the item is linked to the document or embedded in it. Resize handles located on the inside of the border are added to the style, indicating that the item is currently selected. If the item is linked to your document, the dotted border style is used. A solid border is used if the item is embedded.

  if ( pItem == m_pSelection )
    pTracker->m_nStyle |= CRectTracker::resizeInside;

  if ( pItem->GetType( ) == OT_LINK )
    pTracker->m_nStyle |= CRectTracker::dottedLine;
  else
    pTracker->m_nStyle |= CRectTracker::solidLine;

The following code overlays the item with a hatched pattern if the item is currently open.

  if ( pItem->GetItemState( ) ==
           COleClientItem::openState ||
       pItem->GetItemState( ) ==
           COleClientItem::activeUIState )
    pTracker->m_nStyle |= CRectTracker::hatchInside;
}

You can then call this function whenever the tracker has to be displayed. For example, call this function from the OnDraw function of your view class. This updates the tracker’s appearance whenever the view is repainted. For a complete example, see the CMainView::OnDraw function of the MFC OLE sample OCLIENT.

Events will occur in your application that require tracker code, such as resizing, moving, or hit detecting. These actions usually indicate that an attempt is being made to grab or move the item. In these cases, you will need to decide what was grabbed: a resize handle or a portion of the border between resize handles. The OnLButtonDown message handler is a good place to test the position of the mouse in relation to the item. Make a call to CRectTracker::HitTest. If the test returns something besides CRectTracker::hitOutside, the item is being resized or moved. Therefore, you should make a call to the Track member function. See the CMainView::OnLButtonDown function located in the MFC OLE sample OCLIENT for a complete example.

The CRectTracker class provides several different cursor shapes used to indicate whether a move, resize, or drag operation is taking place. To handle this event, check to see whether the item currently under the mouse is selected. If it is, make a call to CRectTracker::SetCursor, or call the default handler. The following example is from the MFC OLE sample OCLIENT:

BOOL CMainView::OnSetCursor( CWnd* pWnd, UINT nHitTest,
  UINT message )
{
  if ( pWnd == this && m_pSelection != NULL )
  {
    // give the tracker for the selection a chance
    CRectTracker tracker;
    SetupTracker( &tracker, m_pSelection );
    if ( tracker.SetCursor( this, nHitTest ))
      return TRUE;
  }
  return CScrollView::OnSetCursor( pWnd,
    nHitTest, message );
}

Rubber-Banding and Trackers

Home | Overview | How Do I | Sample | Tutorial

Another feature supplied with trackers is the “rubber-band” selection, which allows a user to select multiple OLE items by dragging a sizing rectangle around the items to be selected. When the user releases the left mouse button, items within the region selected by the user are selected and can be manipulated by the user. For instance, the user might drag the selection into another container application.

Implementing this feature requires some additional code in your application’s WM_LBUTTONDOWN handler function.

The following code sample implements rubber-band selection and additional features and is taken from the WM_LBUTTONDOWN handler function of MFC General sample TRACKER.

if (pDoc->m_tracker.HitTest(point) < 0)
{
  // just to demonstrate CRectTracker::TrackRubberBand
  CRectTracker tracker;
  if (tracker.TrackRubberBand(this, point,
    pDoc->m_bAllowInvert))
  {
    MessageBeep(0); // beep indicates TRUE

    // see if rubber band intersects
    // with the doc's tracker
    CRect rectT;
    // so intersect rect works
    tracker.m_rect.NormalizeRect();
    if (rectT.IntersectRect(tracker.m_rect,
      pDoc->m_tracker.m_rect))
    {
    // if so, put resize handles on it
    // (i.e. select it)
      if (pDoc->m_tracker.m_nStyle &
        CRectTracker::resizeInside)
      {
      // swap from resize inside to
      // resize outside for effect
        pDoc->m_tracker.m_nStyle &=
          ~CRectTracker::resizeInside;
        pDoc->m_tracker.m_nStyle |=
          CRectTracker::resizeOutside;
      }
      else
      {
      // just use inside resize handles on first time
        pDoc->m_tracker.m_nStyle &=
          ~CRectTracker::resizeOutside;
        pDoc->m_tracker.m_nStyle |=
          CRectTracker::resizeInside;
      }
      pDoc->SetModifiedFlag();
      pDoc->UpdateAllViews(NULL,
        (LPARAM)(LPCRECT)rectSave);
      pDoc->UpdateAllViews(NULL);
    }
  }
}

If you want to allow reversible orientation of the tracker during rubber-banding, you should call CRectTracker::TrackRubberBand with the third parameter set to TRUE. Remember that allowing reversible orientation will sometimes cause CRectTracker::m_rect to become inverted. This can be corrected by a call to CRect::NormalizeRect.

What do you want to know more about?

  • Container client items

  • Customizing drag and drop

See Also CRectTracker


Reusing Code Topics

Home | Overview | How Do I

The Gallery stores code for later sharing or reuse. Such code can be prepackaged components or ActiveX controls, or user-defined components that you have added to the Gallery from your own projects.

You can enhance your projects by using items from the Gallery. The Gallery comes with default folders containing prepackaged Visual C++ Components and Registered ActiveX controls.

You can also add items to the Gallery, and organize the contents of the Gallery by performing ordinary Windows Explorer tasks such as creating new folders and moving items between folders. You can also use other language packages to build your own reusable Gallery components. A component need not be part of a project to reside in the Gallery.

What do you want to do?

  • Access and view Gallery contents

  • Add files to a project

  • Adding a Gallery item to a project

  • Create a Gallery folder

  • Add items to the Gallery

  • View or modify a Gallery item’s properties

  • Organize Gallery items

What do you want to know more about?

  • The Registered ActiveX Controls folder

  • The Visual C++ Components folder


Accessing the Gallery

Home | Overview | How Do I

You can access the Gallery via the Project menu: Point to Add To Project, then click Components and Controls. The Gallery dialog box is similar to a generic file open dialog box.

The Gallery contains two default, system-defined folders called Visual C++ Components and Registered ActiveX Controls, plus folders for any classes that you have added to the Gallery from your own projects.

By default, Gallery items are stored in the directory:

\Program Files\Microsoft Visual Studio\Common\MSDEV98\Gallery

The default folders have the following special considerations:

  • They should not be removed or renamed.

    If you do change the Gallery folder or its default folders, Gallery creates new ones upon invocation. The result is that the new folders contain working links as well as the old ones.

  • They contain only shortcuts and registry information for the files within them.

    Expanding a default folder displays icons that represent shortcuts (links) to the controls or components it contains.

  • Should not be used to store other items, such as files, wizards, and so on.

Also, you should not delete, move, or rename the Gallery folder. Changing the properties of the Gallery folder removes the registry information that the default folders store. For more information, see Organizing Gallery items.

You can also organize the Gallery’s contents by creating and renaming folders. For more information, see Organizing Gallery Items.


Registered ActiveX Controls Folder

Home | Overview | How Do I

This default folder contains shortcuts (links) to all ActiveX controls (.OCX or .DLL files) registered on your system. These controls are either registered automatically by the Setup program, or are controls you purchased and registered separately by running the vendor’s setup program.

The Gallery regenerates links to registered ActiveX controls every time you open it, based on the current state of the registry. This has certain implications:

  • If you delete a link to a registered ActiveX control, the link will still appear the next time you open the Gallery.

  • If you delete a registered ActiveX control (.OCX or .DLL file), but do not unregister it, the link will still appear the next time you open the Gallery. Of course the link will be inoperative.

  • If you copy an ActiveX control to your machine, but do not register the file, the link does not appear because the Gallery does not recognize the control.

To unregister an ActiveX control, see Deleting a Gallery File or Folder.

Tip When you use Windows Explorer to drag an ActiveX control link from a default folder, the Gallery creates a shortcut to the ActiveX control in the new folder so that you don’t have to worry about maintaining it in more than one location.

What do you want to do?

  • Add an ActiveX Control to your project

  • Create an ActiveX Control

  • Add an ActiveX Control to the Gallery

  • Organize Gallery items


Visual C++ Components Folder

Home | Overview | How Do I

This default folder contains shortcuts (links) to the Visual C++ components (.DLL files) registered on your system. These components are either registered automatically by the Setup program, or are components you purchase and register separately by running the vendor’s setup program.

The Gallery regenerates links to registered components every time you open it, based on the current state of the registry. This has certain implications:

  • If you delete a link to a registered component, the link will still appear the next time you open the Gallery.

  • If you delete a registered component (.DLL file), but do not unregister it, the link will still appear the next time you open the Gallery. Of course, the link will be inoperative.

  • If you copy a component to your machine, but do not register the file, the link does not appear because the Gallery does not recognize the component.

To unregister a component, see Deleting a Gallery File or Folder.

Tip When you use Windows Explorer to drag a component link from a default folder, the Gallery creates a shortcut to the component in the new folder so that you don’t have to worry about maintaining it in more than one location.

What do you want to do?

  • Add a component to a project

  • Add a third-party component to the Gallery

  • Organize Gallery items


Adding Gallery Items to a Project

Home | Overview | How Do I

The Gallery provides a convenient way to add complex code such as components and ActiveX controls to your project, or to let you reuse previously written code. Select the Gallery item you want to include in your active project and click the Insert button.

Gallery items are always added to the active project.

The result of inserting a Gallery item into your project depends upon the item you select. For example, inserting a user-defined component (.OGX file) adds the class header (.H) and implementation (.CPP) files as well as any associated resources to the active project.

As another example, suppose you insert an ActiveX control into your project. The Gallery generates a programmatic interface called an ActiveX control wrapper, which allows the ActiveX control to communicate with your program. If the ActiveX control were a dialog gauge to measure program progress, the associated wrapper (a header file and an implementation file) would allow you to write code allowing the gauge to represent program action visually.

Tip Each item in a Gallery default folder has a help topic that you can view by selecting the item and then clicking the More Info button. Components from third-party vendors have their own documentation. You should refer to each component’s documentation to determine its functionality.

What do you want to do?

  • Add files to a project

  • Add an ActiveX Control to a Project

  • Add a component to a Project


Adding Files to a Project

Home | Overview | How Do I

You can add files to a project no matter where the files reside. Note that the Gallery accommodates only recognized components and controls: the default ActiveX controls and components, and .OGX files (components you add to the Gallery from your own projects). Other types of files, such as header files, are not stored in the Gallery. To insert files into the active project workspace, click the Project menu, point to Add To Project, then click Files.

For more information on adding files to a project, see Adding and Removing Files from Projects in the Visual C++ User's Guide.

To add a file to a project

  1. Open the project workspace to which you want to add a file.

    If you have more than one project loaded in the workspace, select the appropriate project: On the Project menu, point to Set Active Project, and click the name.

  2. On the Project menu, point to Add To Project, then click Files.

  3. In the Insert Files into Project dialog box, select the file to add to the project workspace.


Adding an ActiveX Control to a Project

Home | Overview | How Do I

The Gallery stores links to all ActiveX controls registered on your machine in its Registered ActiveX Controls folder. For an ActiveX control that is not registered on your machine, you must first install it, using the vendor’s installation program, before you can add it to a project. You can use ActiveX controls to add features to existing projects.

To obtain information about a registered ActiveX control, select the item, then click the More Info button.

Note You cannot add ActiveX Controls from the Component Gallery to ATL projects without MFC support, Win32 projects, or any other projects without a .clw file.

If you need an ActiveX Control in such a project, use Insert ActiveX Control from the dialog editor's context menu to add the control to the desired dialog(s). If the dialog classes are MFC-based, the wizards will support them, but the control won't appear on the resource palette.

To add a registered ActiveX control to a project

  1. Open the project workspace to which you want to add a control.

    If you have more than one project loaded in the workspace, select the appropriate project: On the Project menu, point to Set Active Project, and click the name.

  2. On the Project menu, point to Add To Project, then click Components and Controls.

  3. In the Components and Controls Gallery dialog box (the Gallery), expand the Registered ActiveX Controls folder and select the ActiveX control you want to add to your project. Click Insert.

  4. The Confirm Classes dialog box appears. Confirm the class information using the Class Confirmation dialog.

What do you want to do?

  • Add items to the Gallery

  • Add a component to a project

  • Add files to a project


Adding a Component to a Project

Home | Overview | How Do I

The Gallery stores links to all components registered on your machine in its Visual C++ Components folder. For a component that is not registered on your machine, you must first install it, using the vendor’s installation program, before you can add it to a project. You can use components to add features to existing projects.

You can also add components that you have previously created in other projects. Such components are called user-defined components and are stored as .OGX files in folders named after the project from which they originated. See Adding Items to the Gallery for more information. The Gallery easily adds user-created components (.OGX files) and Visual C++ components into your projects.

To obtain information about a registered component shown in the Gallery, select the item, then click the More Info button.

To add a component to a project

  1. Open the project workspace to which you want to add a component.

    If you have more than one project loaded in the workspace, select the appropriate project: On the Project menu, point to Set Active Project, and click the name.

  2. On the Project menu, point to Add To Project, then click Components and Controls.

  3. In the Components and Controls Gallery dialog box (the Gallery), expand the Visual C++ Components folder and select the component you want to add to your project.

  4. Click Insert.

  5. At this point you may be prompted with a confirmation dialog box that prompts you to specify the attributes and options of the particular component. The type of information you must confirm or provide depends on the component you are adding. User-defined components and some registered components do not require any confirmation.

  6. Click OK in the confirmation dialog box, if any.

    The Gallery copies the files and resources contained in the component to the active project. The component may modify existing project files and resources without adding any new files.

  7. Use ClassView to inspect the newly added component classes, and ResourceView to see any associated resources.

What do you want to do?

  • Add an ActiveX Control to a Project

  • Add Files to a Project

  • Add Items to the Gallery


Adding Items to the Gallery

Home | Overview | How Do I

You can build and organize your own collection of reusable code by adding items to the Gallery.

You can convert Visual C++ classes from your own projects into reusable components stored in the Gallery. Gallery creates a component that wraps the class, including all pertinent files and resources. You do not have to cut and paste across several files or worry about naming collisions, because Gallery handles the naming. The file extension for components created from Visual C++ classes is .OGX.

Note Do not add ATL classes to the Gallery. ATL classes might appear to be added successfully, but they contain extra information that cannot be saved to the Gallery, and will not work properly when used in other projects.

You can add third-party components or ActiveX controls to the Gallery’s default folders.

You can also move Gallery items into folders you create. For more information, see Organizing Gallery Items.

Files or components that you add to the Gallery should not be read-only or under source control, as such access restrictions might prevent the items from being subsequently added to a project.


Adding Classes to the Gallery

Home | Overview | How Do I

You can convert classes from your own projects into reusable components. The Gallery stores such classes as user-defined components (.OGX files).

To add a class to the Gallery

  1. Open the project workspace in which the class to be added exists.

    If you have more than one project loaded in the workspace, select the appropriate project: On the Project menu, point to Set Active Project, and click the name.

  2. From ClassView, right-click on a class and click Add to Gallery on the shortcut menu.

  3. The Add to Gallery command creates a new folder in the Gallery with the same name as the project. Add to Gallery also creates and places a user-defined component (.OGX file) in the new folder. The .OGX file allows other applications to share the class you added to the Gallery.

    Default Gallery folders are located in:

    \Program Files\Microsoft Visual Studio\Common\MSDEV98\Gallery

In the Gallery, you can rename, move, or copy user-defined components by right-clicking on them and selecting the appropriate command from the shortcut menu.

It is recommended that you not move user-defined components (.OGX file) to the default Gallery folders (Registered ActiveX Controls and Visual C++ Components).


Adding Third-Party Components or ActiveX Controls to the Gallery

Home | Overview | How Do I

To add a third-party component or ActiveX control to the Gallery, run the setup program supplied with the component or ActiveX control. This may include, for example, downloading an ActiveX control from the Internet. This registers the ActiveX control with your system, adding a shortcut to the control in the default Registered ActiveX Controls folder.

Note Not all components provide setup programs. Without a valid setup routine, you cannot add a third-party component or control to the Gallery. To register third-party ActiveX controls, run Regsvr32.exe, which by default is located in:
\Program Files\Microsoft Visual Studio\VC98\bin

To unregister a third-party component or control, see Deleting a Gallery File or Folder.


Organizing Gallery Items

Home | Overview | How Do I

The Gallery initially organizes some components for you into the default Gallery folders: the Visual C++ Components folder and the Registered ActiveX Controls folder. As you add new items to the Gallery, you may want to customize the organization of the Gallery to suit your needs. You can create folders to store items, and you can delete, rename, and rearrange folders you have created.

You can store shortcuts (links) to the Visual C++ Components folder or Registered ActiveX Controls folder using Windows Explorer to drag them from the default folder to a folder you have created. Note that the next time you start Gallery, the shortcuts in the default folders are restored, and the shortcuts in your own folders remain.

What do you want to do?

  • Create a new Gallery folder

  • Rename a Gallery file or folder

  • Change the view of a Gallery folder

  • Move Gallery items from folder to folder

  • Delete a Gallery file or folder

  • View a Gallery item’s properties

  • Get More Help on a Gallery Item

Creating a New Gallery Folder

In the Gallery dialog box, click the New Folder button. (Or right-click in an unused portion of the Gallery’s browser window and select New from the shortcut menu.) This creates an empty folder called “New Folder.”

Renaming a Gallery File or Folder

In the Gallery dialog box, click on the folder name, wait for the cursor to appear, then rename the folder. Or right-click on a folder; from the shortcut menu, select Rename, then specify the new folder name.

Changing the View of a Gallery Folder

In the Gallery dialog, right-click on an unused portion of the browser window. From the shortcut menu, select View, specifying large icons, small icons, file list, or file details. Arrange Icons by name, type, size, or date.

Moving Gallery Items

Use Windows Explorer to drag Gallery items from one location to another.

  • For user-defined components (.OGX files) the file itself is moved or copied.

  • For Visual C++ Components and ActiveX Controls, the Gallery creates a shortcut (link) to the item in the new folder.

Deleting a Gallery File or Folder

You can delete user-defined components and folders in the same way you delete files from the Windows Explorer: By selecting the component or folder in the Gallery dialog box, then pressing the DEL key. Alternately you can right-click on the component or folder, then from the shortcut menu, select Delete.

To remove registered components or ActiveX controls (Microsoft or third-party), you must first uninstall the item by running Regsvr32.exe with the /u option, then delete the item from the Gallery.

Although you can delete the default folders, they will reappear the next time you start Visual C++, and will contain links to the currently registered components and controls. The shortcut (link) to the control is recreated in the default folder because Visual C++ reads the registry information on startup.

Note Deleting the Gallery folder is not recommended. If you delete the Gallery folder, the next time you start Visual C++, the Gallery folder will reappear, but will be empty.

Viewing a Gallery Item’s Properties

You can view the properties (such as version information and file dependencies) of Gallery items using the Properties dialog.

To view properties for a Gallery item, right-click on the item, and then on the shortcut menu click Properties.

Getting More Help on a Gallery Item

You can obtain help on any component or control in the default folders by selecting the item and then clicking More Info.


Serialization Topics

Home | Overview | How Do I | Tutorial

Through class CDocument, MFC provides a default mechanism called serialization for storing data, including objects, in a file. Serialization lets your data objects persist from one program run to another by storing the contents of the objects in a file.

If you wish, you can bypass MFC serialization to create your own mechanism for persistent data storage. You will need to override the class member functions that initiate serialization at the user’s command. See the discussion in Technical Note 22 of the ID_FILE_OPEN, ID_FILE_SAVE, and ID_FILE_SAVE_AS standard commands.

What do you want to know more about?

  • What MFC serialization is all about

  • Serialization examples

  • Class CDocument

  • Class CArchive

  • Class CFile

  • Making my data class serializable

  • Deriving my class from CObject

  • Overriding CDocument::Serialize

  • Using the DECLARE_SERIAL and IMPLEMENT_SERIAL macros

  • Providing a default constructor

  • Serializing an object to or from persistent storage

  • Creating a CArchive object

  • Using the CArchive << and >> operators

  • Data types you can serialize with CArchive

  • Serialization vs. database input/output as ways to manage persistence


Serialization (Object Persistence)

Home | Overview | How Do I | Tutorial

This article explains the serialization mechanism provided in the Microsoft Foundation Class Library (MFC) to allow objects to persist between runs of your program.

“Serialization” is the process of writing or reading an object to or from a persistent storage medium, such as a disk file. MFC supplies built-in support for serialization in the class CObject. Thus, all classes derived from CObject can take advantage of CObject’s serialization protocol.

The basic idea of serialization is that an object should be able to write its current state, usually indicated by the value of its member variables, to persistent storage. Later, the object can be re-created by reading, or deserializing, the object’s state from the storage. Serialization handles all the details of object pointers and circular references to objects that are used when you serialize an object. A key point is that the object itself is responsible for reading and writing its own state. Thus, for a class to be serializable, it must implement the basic serialization operations. As shown in the Serialization group of articles, it is easy to add this functionality to a class.

MFC uses an object of the CArchive class as an intermediary between the object to be serialized and the storage medium. This object is always associated with a CFile object, from which it obtains the necessary information for serialization, including the file name and whether the requested operation is a read or write. The object that performs a serialization operation can use the CArchive object without regard to the nature of the storage medium.

A CArchive object uses overloaded insertion (<<) and extraction (>>) operators to perform writing and reading operations. For more information, see Storing and Loading CObjects via an Archive in the article Serialization: Serializing an Object.

Note Do not confuse the CArchive class with general-purpose iostream classes, which are for formatted text only. The CArchive class is for binary-format serialized objects.

The following articles cover the two main tasks required for serialization:

  • Serialization: Making a Serializable Class

  • Serialization: Serializing an Object

The article Serialization: Serialization vs. Database Input/Output is part of the group of articles on database topics. The article describes when serialization is an appropriate input/output technique in database applications.


Serialization: Making a Serializable Class

Home | Overview | How Do I | Tutorial

Five main steps are required to make a class serializable. They are listed below and explained in the following sections:

  1. Deriving your class from CObject (or from some class derived from CObject).

  2. Overriding the Serialize member function.

  3. Using the DECLARE_SERIAL macro in the class declaration.

  4. Defining a constructor that takes no arguments.

  5. Using the IMPLEMENT_SERIAL macro in the implementation file for your class.

If you call Serialize directly rather than through the >> and << operators of CArchive, the last three steps are not required for serialization.

Deriving Your Class from CObject

The basic serialization protocol and functionality are defined in the CObject class. By deriving your class from CObject (or from a class derived from CObject), as shown in the following declaration of class CPerson, you gain access to the serialization protocol and functionality of CObject.

Overriding the Serialize Member Function

The Serialize member function, which is defined in the CObject class, is responsible for actually serializing the data necessary to capture an object’s current state. The Serialize function has a CArchive argument that it uses to read and write the object data. The CArchive object has a member function, IsStoring, which indicates whether Serialize is storing (writing data) or loading (reading data). Using the results of IsStoring as a guide, you either insert your object’s data in the CArchive object with the insertion operator (<<) or extract data with the extraction operator (>>).

Consider a class that is derived from CObject and has two new member variables, of types CString and WORD. The following class declaration fragment shows the new member variables and the declaration for the overridden Serialize member function:

class CPerson : public CObject
{
public:
    DECLARE_SERIAL( CPerson )
    // empty constructor is necessary
    CPerson(){};

    CString m_name;
    WORD   m_number;

    void Serialize( CArchive& archive );

    // rest of class declaration
};

To override the Serialize member function

  1. Call your base class version of Serialize to make sure that the inherited portion of the object is serialized.

  2. Insert or extract the member variables specific to your class.

    The insertion and extraction operators interact with the archive class to read and write the data. The following example shows how to implement Serialize for the CPerson class declared above:

    void CPerson::Serialize( CArchive& archive )
{
    // call base class function first
    // base class is CObject in this case
    CObject::Serialize( archive );

    // now do the stuff for our specific class
    if( archive.IsStoring() )
        archive << m_name << m_number;
    else
        archive >> m_name >> m_number;
}

You can also use the CArchive::Read and CArchive::Write member functions to read and write large amounts of untyped data.

Using the DECLARE_SERIAL Macro

The DECLARE_SERIAL macro is required in the declaration of classes that will support serialization, as shown here:

class CPerson : public CObject
{
    DECLARE_SERIAL( CPerson )
    // rest of declaration follows...
};

Defining a Constructor with No Arguments

MFC requires a default constructor when it re-creates your objects as they are deserialized (loaded from disk). The deserialization process will fill in all member variables with the values required to re-create the object.

This constructor can be declared public, protected, or private. If you make it protected or private, you ensure that it will only be used by the serialization functions. The constructor must put the object in a state that allows it to be safely deleted if necessary.

Note If you forget to define a constructor with no arguments in a class that uses the DECLARE_SERIAL and IMPLEMENT_SERIAL macros, you will get a “no default constructor available” compiler warning on the line where the IMPLEMENT_SERIAL macro is used.

Using the IMPLEMENT_SERIAL Macro in the Implementation File

The IMPLEMENT_SERIAL macro is used to define the various functions needed when you derive a serializable class from CObject. You use this macro in the implementation file (.CPP) for your class. The first two arguments to the macro are the name of the class and the name of its immediate base class.

The third argument to this macro is a schema number. The schema number is essentially a version number for objects of the class. Use an integer greater than or equal to 0 for the schema number. (Don’t confuse this schema number with database terminology.)

The MFC serialization code checks the schema number when reading objects into memory. If the schema number of the object on disk does not match the schema number of the class in memory, the library will throw a CArchiveException, preventing your program from reading an incorrect version of the object.

If you want your Serialize member function to be able to read multiple versions — that is, files written with different versions of the application — you can use the value VERSIONABLE_SCHEMA as an argument to the IMPLEMENT_SERIAL macro. For usage information and an example, see the GetObjectSchema member function of class CArchive.

The following example shows how to use IMPLEMENT_SERIAL for a class, CPerson, that is derived from CObject:

IMPLEMENT_SERIAL( CPerson, CObject, 1 )

Once you have a serializable class, you can serialize objects of the class, as discussed in the article Serialization: Serializing an Object.


Serialization: Serializing an Object

Home | Overview | How Do I | Tutorial

The article Serialization: Making a Serializable Class shows how to make a class serializable. Once you have a serializable class, you can serialize objects of that class to and from a file via a CArchive object. This article explains:

  • What a CArchive object is.

  • Two ways to create a CArchive.

  • How to use the CArchive << and >> operators.

  • Storing and loading CObjects via an archive.

You can let the framework create the archive for your serializable document or explicitly create the CArchive object yourself. You can transfer data between a file and your serializable object by using the << and >> operators for CArchive or, in some cases, by calling the Serialize function of a CObject-derived class.

What Is a CArchive Object

A CArchive object provides a type-safe buffering mechanism for writing or reading serializable objects to or from a CFile object. Usually the CFile object represents a disk file; however, it can also be a memory file (CSharedFile object), perhaps representing the Clipboard.

A given CArchive object either stores (writes, serializes) data or loads (reads, deserializes) data, but never both. The life of a CArchive object is limited to one pass through writing objects to a file or reading objects from a file. Thus, two successively created CArchive objects are required to serialize data to a file and then deserialize it back from the file.

When an archive stores objects to a file, the archive attaches the CRuntimeClass name to the objects. Then, when another archive loads objects from a file to memory, the CObject-derived objects are dynamically reconstructed based on the CRuntimeClass of the objects. A given object may be referenced more than once as it is written to the file by the storing archive. The loading archive, however, will reconstruct the object only once. The details about how an archive attaches CRuntimeClass information to objects and reconstructs objects, taking into account possible multiple references, are described in Technical Note 2.

As data is serialized to an archive, the archive accumulates the data until its buffer is full. Then the archive writes its buffer to the CFile object pointed to by the CArchive object. Similarly, as you read data from an archive, it reads data from the file to its buffer and then from the buffer to your deserialized object. This buffering reduces the number of times a hard disk is physically read, thus improving your application’s performance.

Two Ways to Create a CArchive Object

There are two ways to create a CArchive object:

  • Implicit creation of a CArchive object via the framework

  • Explicit creation of a CArchive object

Implicit Creation of a CArchive Object via the Framework

The most common, and easiest, way is to let the framework create a CArchive object for your document on behalf of the Save, Save As, and Open commands on the File menu.

Here is what the framework does when the user of your application issues the Save As command from the File menu:

  1. Presents the Save As dialog box and gets the filename from the user.

  2. Opens the file named by the user as a CFile object.

  3. Creates a CArchive object that points to this CFile object. In creating the CArchive object, the framework sets the mode to “store” (write, serialize), as opposed to “load” (read, deserialize).

  4. Calls the Serialize function defined in your CDocument-derived class, passing it a reference to the CArchive object.

Your document’s Serialize function then writes data to the CArchive object, as explained shortly. Upon return from your Serialize function, the framework destroys the CArchive object and then the CFile object.

Thus, if you let the framework create the CArchive object for your document, all you have to do is implement the document’s Serialize function that writes and reads to and from the archive. You also have to implement Serialize for any CObject-derived objects that the document’s Serialize function in turn serializes directly or indirectly.

Explicit Creation of a CArchive Object

Besides serializing a document via the framework, there are other occasions when you may need a CArchive object. For example, you might want to serialize data to and from the Clipboard, represented by a CSharedFile object. Or, you may want to use a user interface for saving a file that is different from the one offered by the framework. In this case, you can explicitly create a CArchive object. You do this the same way the framework does, using the following procedure.

To explicitly create a CArchive object

  1. Construct a CFile object or an object derived from CFile.

  2. Pass the CFile object to the constructor for CArchive, as shown in the following example:
    CFile theFile;
theFile.Open(..., CFile::modeWrite);
CArchive archive(&theFile, CArchive::store);

    The second argument to the CArchive constructor is an enumerated value that specifies whether the archive will be used for storing or loading data to or from the file. The Serialize function of an object checks this state by calling the IsStoring function for the archive object.

When you are finished storing or loading data to or from the CArchive object, close it. Although the CArchive (and CFile) objects will automatically close the archive (and file), it is good practice to explicitly do so since it makes recovery from errors easier. For more information about error handling, see the article Exceptions: Catching and Deleting Exceptions.

To close the CArchive object

  • The following example illustrates how to close the CArchive object:
    archive.Close();
theFile.Close();

Using the CArchive << and >> Operators

CArchive provides << and >> operators for writing and reading simple data types as well as CObjects to and from a file.

To store an object in a file via an archive

  • The following example shows how to store an object in a file via an archive:
    CArchive ar(&theFile, CArchive::store);
WORD wEmployeeID;
...
ar << wEmployeeID;

To load an object from a value previously stored in a file

  • The following example shows how to load an object from a value previously stored in a file:
    CArchive ar(&theFile, CArchive::load);
WORD wEmployeeID;
...
ar >> wEmployeeID;

Usually, you store and load data to and from a file via an archive in the Serialize functions of CObject-derived classes, which you must have declared with the DECLARE_SERIALIZE macro. A reference to a CArchive object is passed to your Serialize function. You call the IsLoading function of the CArchive object to determine whether the Serialize function has been called to load data from the file or store data to the file.

The Serialize function of a serializable CObject-derived class typically has the following form:

void CPerson::Serialize(CArchive& ar)
{
    CObject::Serialize(ar);
    if (ar.IsStoring())
    {
        // TODO:  add storing code here
    }
    else
    {
    // TODO:  add loading code here
    }
}

The above code template is exactly the same as the one AppWizard creates for the Serialize function of the document (a class derived from CDocument). This code template helps you write code that is easier to review, because the storing code and the loading code should always be parallel, as in the following example:

void CPerson:Serialize(CArchive& ar)
{
    if (ar.IsStoring())
    {
        ar << m_strName;
        ar << m_wAge;
    }
    else
    {
        ar >> m_strName;
        ar >> m_wAge;
    }
}

The library defines << and >> operators for CArchive as the first operand and the following data types and class types as the second operand:

CObject* | SIZE and CSize | float
WORD | CString | POINT and CPoint
DWORD | BYTE | RECT and CRect
double | LONG | CTime and CTimeSpan
int | COleCurrency | COleVariant
COleDateTime | COleDateTimeSpan |

Note Storing and loading CObjects via an archive requires extra consideration. For more information see Storing and Loading CObjects via an Archive below.

The CArchive << and >> operators always return a reference to the CArchive object, which is the first operand. This enables you to chain the operators, as illustrated below:

BYTE bSomeByte;
WORD wSomeWord;
DWORD wSomeDoubleWord;
...
ar << bSomeByte << wSomeWord << wSomeDoubleWord;

Storing and Loading CObjects via an Archive

Storing and loading CObjects via an archive requires extra consideration. In certain cases, you should call the Serialize function of the object, where the CArchive object is a parameter of the Serialize call, as opposed to using the << or >> operator of the CArchive. The important fact to keep in mind is that the CArchive >> operator constructs the CObject in memory based on CRuntimeClass information previously written to the file by the storing archive.

Therefore, whether you use the CArchive << and >> operators, versus calling Serialize, depends on whether you need the loading archive to dynamically reconstruct the object based on previously stored CRuntimeClass information. Use the Serialize function in the following cases:

  • When deserializing the object, you know the exact class of the object beforehand.

  • When deserializing the object, you already have memory allocated for it.

Caution If you load the object using the Serialize function, you must also store the object using the Serialize function. Don’t store using the CArchive << operator and then load using the Serialize function, or store using the Serialize function and then load using CArchive >> operator.

The following example illustrates the cases:

class CMyObject : public CObject
{
// ...Member functions
   public:
   CMyObject() { }
   virtual void Serialize( CArchive& ar ) { }

// Implementation
   protected:
   DECLARE_SERIAL( CMyObject )
};

class COtherObject : public CObject
{
   // ...Member functions
   public:
   COtherObject() { }
   virtual void Serialize( CArchive& ar ) { }

// Implementation
protected:
   DECLARE_SERIAL( COtherObject )
};

class CCompoundObject : public CObject
{
   // ...Member functions
   public:
   CCompoundObject();
   virtual void Serialize( CArchive& ar );

// Implementation
protected:
   CMyObject m_myob;    // Embedded object
   COtherObject* m_pOther;    // Object allocated in constructor
   CObject* m_pObDyn;    // Dynamically allocated object
   //..Other member data and implementation

   DECLARE_SERIAL( CCompoundObject )
};

IMPLEMENT_SERIAL(CMyObject,CObject,1)
IMPLEMENT_SERIAL(COtherObject,CObject,1)
IMPLEMENT_SERIAL(CCompoundObject,CObject,1)

CCompoundObject::CCompoundObject()
{
   m_pOther = new COtherObject; // Exact type known and object already
            //allocated.
   m_pObDyn = NULL;    // Will be allocated in another member function
            // if needed, could be a derived class object.
}

void CCompoundObject::Serialize( CArchive& ar )
{
   CObject::Serialize( ar );    // Always call base class Serialize.
   m_myob.Serialize( ar );    // Call Serialize on embedded member.
   m_pOther->Serialize( ar );    // Call Serialize on objects of known exact type.

   // Serialize dynamic members and other raw data
   if ( ar.IsStoring() )
   {
      ar << m_pObDyn;
      // Store other members
   }
   else
   {
      ar >> m_pObDyn; // Polymorphic reconstruction of persistent
            // object
            //load other members
   }
}

In summary, if your serializable class defines an embedded CObject as a member, you should not use the CArchive << and >> operators for that object, but should call the Serialize function instead. Also, if your serializable class defines a pointer to a CObject (or an object derived from CObject) as a member, but constructs this other object in its own constructor, you should also call Serialize.


Serialization: Serialization vs. Database Input/Output

Home | Overview | How Do I | Tutorial

This article explains when to use document objects and serialization for file-based input/output (I/O) and when other I/O techniques are appropriate — because the application reads and writes data on a per-transaction basis, as in database applications. If you don’t use serialization, you also won’t need the File Open, Save, and Save As commands. Topics covered include:

  • Deciding how your application will handle input/output

  • Handling the File menu in database applications

Deciding How to Handle Input/Output

Whether you use file-based I/O or not depends on how you respond to the questions in the following decision tree, which begins with the question:

Does the primary data in your application reside in a disk file?

  1. Yes, the primary data resides in a disk file.

    Does the application read the whole file into memory on File Open and write the whole file back to disk on File Save?

  2. Yes — this is the default MFC document case.

    Use CDocument serialization.

  3. No — this is typically the case of transaction-based updating of the file.

    The MFC Advanced Concepts sample CHKBOOK is an example of this case. You update the file on a per-transaction basis and don’t need CDocument serialization.

  4. No, the primary data doesn’t reside in a disk file.

    Does the data reside in an ODBC data source?

  5. Yes, the data resides in an ODBC data source.

    Use MFC’s database support. The standard MFC implementation for this case includes a CDocument object that stores a CDatabase object, as discussed in the article What Is the MFC Database Programming Model?. The application might also read and write an auxiliary file — the purpose of the AppWizard “both a database view and file support” option. In this case, you’d use serialization for the auxiliary file.

  6. No, the data doesn’t reside in an ODBC data source.

    Examples of this case: the data resides in a non-ODBC DBMS; the data is read via some other mechanism, such as OLE or DDE.

    In such cases, you won’t use serialization, and your application won’t have Open and Save menu items. You might still want to use a CDocument as a “home base,” just as an MFC ODBC application uses the document to store CRecordset objects. But you won’t use the framework’s default File Open/Save document serialization.

To support the Open, Save, and Save As commands on the File menu, the framework provides document serialization. Serialization reads and writes data, including objects derived from class CObject, to permanent storage, normally a disk file. Serialization is easy to use and serves many of your needs, but it may be inappropriate in many data-access applications. Data-access applications typically update data on a “per-transaction” basis. They update the records affected by the transaction rather than reading and writing a whole data file at once.

For general information about serialization, see the article Serialization (Object Persistence).

The File Menu in an MFC Database Application

If you create an MFC database application and don’t use serialization, how should you interpret the Open, Close, Save, and Save As commands on the File menu? While there are no style guidelines for this question, here are a few suggestions:

  • Eliminate the File menu’s Open command entirely.

  • Interpret the Open command as “open database” and show the user a list of data sources your application recognizes.

  • Interpret the Open command as, perhaps, “open profile.” Retain Open for opening a serialized file, but use the file to store a serialized document containing “user profile” information, such as the user’s preferences, including his or her login ID (optionally excluding the password) and the data source he or she most recently worked with.

AppWizard supports creating an application with no document-related File menu commands. Select the “A database view, without file support” option on the database options page.

To interpret a File menu command in a special way, you must override one or more command handlers, mostly in your CWinApp-derived class. For example, if you completely override OnFileOpen (which implements the ID_FILE_OPEN command) to mean “open database”:

  • Don’t call the base class version of OnFileOpen, since you’re completely replacing the framework’s default implementation of the command.

  • Use the handler instead to display a dialog box listing data sources. You can display such a dialog by calling CDatabase::OpenEx or CDatabase::Open with the parameter NULL. This opens an ODBC dialog box that displays all available data sources on the user’s machine.

  • Because database applications typically don’t save a whole document, you’ll probably want to remove the Save and Save As implementations unless you use a serialized document to store profile information. Otherwise, you might implement the Save command as, for example, “commit transaction.” See Technical Note 22 for more information about overriding these commands.


Strings Topics

Home | Overview | How Do I

Visual C++ supplies several ways to work with character-string data. These include MFC’s CString class, functions in the run-time library, and Win32 API functions.

This family of articles covers the CString class in MFC. For information about alternative ways to work with strings, see the overview.

What do you want to know more about?

CString Fundamentals

  • Class CString

  • CString semantics

  • CString and standard C strings

  • CString operations: accessing characters, concatenating strings, comparing strings

  • CString operations relating to C-style strings

  • CString and the run-time library string functions

CString Operations

  • Allocating CString objects

  • Directly accessing the characters in a CString

  • Directly modifying CString contents

  • Converting a CString to a C-style null-terminated string

  • Specifying CString formal parameters in my functions

  • CString argument passing

  • CString as a function output

  • Using CString with variable argument functions

CString Support for Unicode and Multibyte Character Strings (MBCS)

  • Unicode

  • MBCS

  • Unicode and multibyte character string support in CString

  • The TCHAR data type and the _T macro

Advanced CString Topics

  • The BSTR data type used in Automation

  • CString reference counting for efficiency

  • CString and exceptions


Strings in MFC

Home | Overview | How Do I

This article describes the general-purpose services that the class library provides related to string manipulation. Topics covered in this article include:

  • Unicode and MBCS provide portability

  • CStrings and const char pointers

  • CString reference counting

The CString class provides support for manipulating strings. It is intended to replace and extend the functionality normally provided by the C run-time library string package. The CString class supplies member functions and operators for simplified string handling, similar to those found in Basic. The class also provides constructors and operators for constructing, assigning, and comparing CStrings and standard C++ string data types. Because CString is not derived from CObject, you can use CString objects independently of most of the Microsoft Foundation Class Library (MFC).

CString objects follow “value semantics.” A CString object represents a unique value. Think of a CString as an actual string, not as a pointer to a string.

A CString object represents a sequence of a variable number of characters. CString objects can be thought of as arrays of characters.

Unicode and MBCS Provide Portability

With MFC version 3.0 and later, MFC, including CString, is enabled for both Unicode and Multibyte Character Sets (MBCS). This support makes it easier for you to write portable applications that you can build for either Unicode or ANSI characters. To enable this portability, each character in a CString object is of type TCHAR, which is defined as wchar_t if you define the symbol _UNICODE when you build your application, or as char if not. A wchar_t character is 16 bits wide. (Unicode is available only under Windows NT.) MBCS is enabled if you build with the symbol _MBCS defined. MFC itself is built with either the _MBCS symbol (for the NAFX libraries) or the _UNICODE symbol (for the UAFX libraries) defined.

Note The CString examples in this and the accompanying articles on strings show literal strings properly formatted for Unicode portability, using the _T macro, which translates the literal string to the form

L"literal string"

which the compiler treats as a Unicode string. For example, the following code:

CString strName = _T("Name");

is translated as a Unicode string if _UNICODE is defined or as an ANSI string if not. For more information, see the article Strings: Unicode and Multibyte Character Set (MBCS) Support.

A CString object can store up to INT_MAX (2,147,483,647) characters. The TCHAR data type is used to get or set individual characters inside a CString object. Unlike character arrays, the CString class has a built-in memory allocation capability. This allows CString objects to automatically grow as needed (that is, you don’t have to worry about growing a CString object to fit longer strings).

CStrings and const char Pointers

A CString object also can act like a literal C-style string (an LPCTSTR, which is the same as const char* if not under Unicode). The LPCTSTR conversion operator allows CString objects to be freely substituted for character pointers in function calls. The CString( LPCTSTR lpsz ) constructor allows character pointers to be substituted for CString objects.

No attempt is made to fold CString objects. If you make two CString objects containing Chicago, for example, the characters in Chicago are stored in two places. (This may not be true of future versions of MFC, so you should not depend on it.)

Tips Use the GetBuffer and ReleaseBuffer member functions when you need to directly access a CString as a nonconstant pointer to a character (LPTSTR instead of a const character pointer, LPCTSTR).

Use the AllocSysString and SetSysString member functions to allocate and set BSTR objects used in Automation (formerly known as OLE Automation).

Where possible, allocate CString objects on the frame rather than on the heap. This saves memory and simplifies parameter passing.

The CString class is not implemented as a Microsoft Foundation Class Library collection class, though CString objects can certainly be stored as elements in collections.

CString Reference Counting

As of MFC version 4.0, when CString objects are copied, MFC increments a reference count rather than copying the data. This makes passing parameters by value and returning CString objects by value more efficient. These operations cause the copy constructor to be called, sometimes more than once. Incrementing a reference count reduces that overhead for these common operations and makes using CString a more attractive option.

As each copy is destroyed, the reference count in the original object is decremented. The original CString object is not destroyed until its reference count is reduced to zero.

You can use the CString member functions LockBuffer and UnlockBuffer to disable or enable reference counting.

Further Reading About Strings

The following articles provide more information about CString:

  • Strings: Basic CString Operations

  • Strings: CString Semantics

  • Strings: CString Operations Relating to C-Style Strings

  • Strings: CString Exception Cleanup

  • Strings: CString Argument Passing

  • Strings: Unicode and Multibyte Character Set (MBCS) Support


Strings: Basic CString Operations

Home | Overview | How Do I

This article explains basic CString operations, including:

  • Creating CString objects from standard C literal strings

  • Accessing individual characters in a CString

  • Concatenating two CString objects

  • Comparing CString objects

The CString class provides member functions and overloaded operators that duplicate and, in some cases, surpass the string services of the C run-time libraries (for example, strcat).

Creating CString Objects from Standard C Literal Strings

You can assign C-style literal strings to a CString just as you can assign one CString object to another:

  • Assign the value of a C literal string to a CString object:
    CString myString = "This is a test";
  • Assign the value of one CString to another CString object:
    CString oldString = "This is a test";
CString newString = oldString;

    The contents of a CString object are copied when one CString object is assigned to another. Thus, the two strings do not share a reference to the actual characters that make up the string. For more information on using CString objects as values, see the article Strings: CString Semantics.

Tip To write your application so that it can be compiled for Unicode or for ANSI, code literal strings using the _T macro. For more information, see the article Strings: Unicode and Multibyte Character Set (MBCS) Support.

Accessing Individual Characters in a CString

You can access individual characters within a CString object with the GetAt and SetAt member functions. You can also use the array element, or subscript, operator ( [ ] ) instead of GetAt to get individual characters (this is similar to accessing array elements by index, as in standard C-style strings). Index values for CString characters are zero-based.

Concatenating Two CString Objects

To concatenate two CString objects, use the concatenation operators (+ or +=) as follows:

CString s1 = "This ";        //Cascading concatenation
s1 += "is a ";
CString s2 = "test";
CString message = s1 + "big " + s2;
//Message contains "This is a big test".

At least one of the arguments to the concatenation operators (+ or +=) must be a CString object, but you can use a constant character string (such as "big") or a char (such as ‘x’) for the other argument.

Comparing CString Objects

The Compare member function and the == operator for CString are equivalent. Compare, operator==, and CompareNoCase are MBCS- and Unicode-aware; CompareNoCase is also case insensitive. The Collate member function of CString is locale sensitive and is often slower than Compare. Collate should be used only where it is necessary to abide by the sorting rules as specified by the current locale.

The following table shows the available CString comparison functions and their equivalent Unicode/MBCS-portable functions in the C run-time library:

CString function | MBCS function | Unicode function
Compare | _mbscmp | wcscmp
CompareNoCase | _mbsicmp | _wcsicmp
Collate | _mbscoll | wcscoll

The CString class overrides the relational operators (<, <=, >=, >, ==, and !=).You can compare two CStrings using these operators, as shown here:

CString s1( "Tom" );
CString s2( "Jerry" );
if( s1 < s2 )
    ...


Strings: CString Semantics

Home | Overview | How Do I

Even though CString objects are dynamically growable objects, they act like built-in primitive types and simple classes. Each CString object represents a unique value. CString objects should be thought of as the actual strings rather than as pointers to strings.

The most obvious consequence of using CString objects as values is that the string contents are copied when you assign one CString to another. Thus, even though two CString objects may represent the same sequence of characters, they do not share those characters. Each CString has its own copy of the character data. When you modify one CString object, the copied CString object is not modified, as shown by the following example:

CString s1, s2;
s1 = s2 = "hi there";

if( s1 == s2 )            // TRUE - they are equal
    ...

s1.MakeUpper();        // Does not modify s2
if( s2[0] == 'h' )        // TRUE - s2 is still "hi there"

Notice in the example that the two CString objects are considered “equal” because they represent the same character string. The CString class overloads the equality operator (==) to compare two CString objects based on their value (contents) rather than their identity (address).


Strings: CString Operations Relating to C-Style Strings

Home | Overview | How Do I

It is often useful to manipulate the contents of a CString object as if it were a C-style null-terminated string. This article covers the following topics:

  • Converting to C-style null-terminated strings

  • Working with standard run-time library string functions

  • Modifying CString contents directly

  • Using CString objects with variable argument functions

  • Specifying CString formal parameters

Converting to C-Style Null-Terminated Strings

Consider the following two cases:

  • In the simplest case, you can cast a CString object to be an LPCTSTR. The LPCTSTR type conversion operator returns a pointer to a read-only C-style null-terminated string from a CString object.

    The pointer returned by LPCTSTR points into the data area used by the CString. If the CString goes out of scope and is automatically deleted or something else changes the contents of the CString, the LPCTSTR pointer will no longer be valid. Treat the string to which the pointer points as temporary.

  • You can use CString functions, such as SetAt, to modify individual characters in the string object. However, if you need a copy of a CString object’s characters that you can modify directly, use strcpy (or the Unicode/MBCS-portable _tcscpy) to copy the CString object into a separate buffer where the characters can be safely modified, as shown by the following example:
    CString theString( "This is a test" );
LPTSTR lpsz = new TCHAR[theString.GetLength()+1];
_tcscpy(lpsz, theString);
//... modify lpsz as much as you want

    Note The second argument to strcpy (or the Unicode/MBCS-portable _tcscpy) is either a const wchar_t* (Unicode) or a const char* (ANSI). The example above passes a CString for this argument. The C++ compiler automatically applies the conversion function defined for the CString class that converts a CString to an LPCTSTR. The ability to define casting operations from one type to another is one of the most useful features of C++.

Working with Standard Run-Time Library String Functions

In most situations, you should be able to find CString member functions to perform any string operation for which you might consider using the standard C run-time library string functions, such as strcmp (or the Unicode/MBCS-portable _tcscmp).

If you need to use the C run-time string functions, you can use the techniques described in Converting to C-Style Null-Terminated Strings to copy the CString object to an equivalent C-style string buffer, perform your operations on the buffer, and then assign the resulting C-style string back to a CString object.

Modifying CString Contents Directly

In most situations, you should use CString member functions to modify the contents of a CString object or to convert the CString to a C-style character string.

However, there are certain situations, such as working with operating-system functions that require a character buffer, where it is advantageous to directly modify the CString contents.

The GetBuffer and ReleaseBuffer member functions allow you to gain access to the internal character buffer of a CString object and modify it directly. The following steps show how to use these functions for this purpose:

  1. Call GetBuffer for a CString object, specifying the length of the buffer you require.

  2. Use the pointer returned by GetBuffer to write characters directly into the CString object.

  3. Call ReleaseBuffer for the CString object to update all the internal CString state information (such as the length of the string). After modifying a CString object’s contents directly, you must call ReleaseBuffer before calling any other CString member functions.

Using CString Objects with Variable Argument Functions

Some C functions take a variable number of arguments. A notable example is printf. Because of the way this kind of function is declared, the compiler cannot be sure of the type of the arguments and cannot determine which conversion operation to perform on each argument. Therefore, it is essential that you use an explicit type cast when passing a CString object to a function that takes a variable number of arguments.

To use a CString object in a variable argument function

  • Explicitly cast the CString to an LPCTSTR string, as shown here:
    CString kindOfFruit = "bananas";
int        howmany = 25;
printf( "You have %d %s\n", howmany, (LPCTSTR)kindOfFruit );

Specifying CString Formal Parameters

For most functions that need a string argument, it is best to specify the formal parameter in the function prototype as a const pointer to a character (LPCTSTR) instead of a CString. When a formal parameter is specified as a const pointer to a character, you can pass either a pointer to a TCHAR array, a literal string ["hi there"], or a CString object. The CString object will be automatically converted to an LPCTSTR. Any place you can use an LPCTSTR, you can also use a CString object.

You can also specify a formal parameter as a constant string reference (that is, const CString&) if the argument will not be modified. Drop the const modifier if the string will be modified by the function. If a default null value is desired, initialize it to the null string [""], as shown below:

void AddCustomer( const CString& name,
                    const CString& address,
                    const CString& comment = "" );

For most function results, you can simply return a CString object by value.

See Also Strings: CString Argument Passing


Strings: CString Exception Cleanup

Home | Overview | How Do I

In previous versions of MFC, it was important that you clean up CString objects after use. With MFC version 3.0 and later, explicit cleanup is no longer necessary.

Under the C++ exception handling mechanism that MFC now uses, you don’t have to worry about cleanup after an exception. For a description of how C++ “unwinds” the stack after an exception is caught, see Exception Handling Topics (C++). Even if you use the MFC TRY/CATCH macros instead of the C++ keywords try and catch, MFC uses the C++ exception mechanism underneath, so you still don’t need to clean up explicitly.

See Also Exception Handling Topics (MFC)


Strings: CString Argument Passing

Home | Overview | How Do I

This article explains how to pass CString objects to functions and how to return CString objects from functions.

CString Argument-Passing Conventions

When you define a class interface, you must determine the argument-passing convention for your member functions. There are some standard rules for passing and returning CString objects. If you follow the rules described in Strings as Function Inputs and Strings as Function Outputs, you will have efficient, correct code.

Strings as Function Inputs

If a string is an input to a function, in most cases it is best to declare the string function parameter as LPCTSTR. Convert to a CString object as necessary within the function using constructors and assignment operators. If the string contents are to be changed by a function, declare the parameter as a nonconstant CString reference (CString&).

Strings as Function Outputs

Normally you can return CString objects from functions because CString objects follow value semantics like primitive types. To return a read-only string, use a constant CString reference (const CString&). The following example illustrates the use of CString parameters and return types:

class CName : public CObject
{
private:
    CString m_firstName;
    char m_middleInit;
    CString m_lastName;
public:
    CName() {}
    void SetData( LPCTSTR fn, const char mi, LPCTSTR ln )
    {
        m_firstName = fn;
        m_middleInit = mi;
        m_lastName = ln;
    }
    void GetData( CString& cfn, char mi, CString& cln )
    {
        cfn = m_firstName;
        mi = m_middleInit;
        cln = m_lastName;
    }
    CString GetLastName()
    {
        return m_lastName;
    }
};
...
CName name;
CString last, first;
TCHAR middle;
name.SetData( "John", 'Q', "Public" );
ASSERT( name.GetLastName() == "Public" );
name.GetData( first, middle, last );
ASSERT( ( first == "John" ) && ( last == "Public" ) );
...


Strings: Unicode and Multibyte Character Set (MBCS) Support

Home | Overview | How Do I

Some international markets use languages, such as Japanese and Chinese, with large character sets. To support programming for these markets, the Microsoft Foundation Class Library (MFC) is enabled for two different approaches to handling large character sets:

  • Unicode

  • Multibyte Character Sets (MBCS)

MFC Support for Unicode Strings

The entire class library is conditionally enabled for Unicode characters and strings. In particular, class CString is Unicode-enabled.

Note The Unicode versions of the MFC libraries are not copied to your hard drive unless you select them during a Custom installation. They are not copied during other types of installation. If you attempt to build or run an MFC Unicode application without the MFC Unicode files, you may get errors.

To copy the files to your hard drive, rerun Setup, choose Custom installation, clear the check boxes for all other components except "Microsoft Foundation Class Libraries," click the Details button, and select both "Static Library for Unicode" and "Shared Library for Unicode." This will copy the following files to your hard drive:

UAFXCW.LIB | UAFXCW.PDB | UAFXCWD.LIB | UAFXCWD.PDB
MFCxxU.LIB | MFCxxU.DBG | MFCxxU.DLL | MFCxxUD.LIB
MFCxxUD.PDB | MFCxxUD.DLL | MFCDxxUD.LIB | MFCDxxUD.PDB
MFCDxxUD.DLL | MFCNxxUD.LIB | MFCNxxUD.PDB | MFCNxxUD.DLL
MFCOxxUD.LIB | MFCOxxUD.PDB | MFCOxxUD.DLL |

Where xx represents the version number of the file; for example, ‘42’ represents version 4.2.

CString is based on the TCHAR data type. If the symbol _UNICODE is defined for a build of your program, TCHAR is defined as type wchar_t, a 16-bit character encoding type; otherwise, it is defined as char, the normal 8-bit character encoding. Under Unicode, then, CStrings are composed of 16-bit characters. Without Unicode, they are composed of characters of type char.

To complete Unicode programming of your application, you must also:

  • Use the _T macro to conditionally code literal strings to be portable to Unicode.

  • When you pass strings, pay attention to whether function arguments require a length in characters or a length in bytes. The difference is important if you’re using Unicode strings.

  • Use portable versions of the C run-time string-handling functions.

  • Use the following data types for characters and character pointers:

    TCHAR Where you would use char.

    LPTSTR Where you would use char*.

    LPCTSTR Where you would use const char*. CString provides the operator LPCTSTR to convert between CString and LPCTSTR.

CString also supplies Unicode-aware constructors, assignment operators, and comparison operators.

For related information on Unicode programming, see Unicode and MBCS and Unicode Topics. The Run-Time Library Reference defines portable versions of all of its string-handling functions. See the category Internationalization.

MFC Support for MBCS Strings

The class library is also enabled for multibyte character sets — specifically for double-byte character sets (DBCS).

Under this scheme, a character can be either one or two bytes wide. If it is two bytes wide, its first byte is a special “lead byte,” chosen from a particular range depending on which code page is in use. Taken together, the lead and “trail bytes” specify a unique character encoding.

If the symbol _MBCS is defined for a build of your program, type TCHAR, on which CString is based, maps to char. It’s up to you to determine which bytes in a CString are lead bytes and which are trail bytes. The C run-time library supplies functions to help you determine this.

Under DBCS, a given string can contain all single-byte ANSI characters, all double-byte characters, or a combination of the two. These possibilities require special care in parsing strings, including CString objects.

Note Unicode string serialization in MFC can read both Unicode and MBCS strings regardless of which version of the application you are running. Because of this, your data files are portable between Unicode and MBCS versions of your program.

CString member functions use special “generic text” versions of the C run-time functions they call, or they use Unicode-aware functions such as lstrlen or lstrcpy. Thus, for example, if a CString function would normally call strcmp, it calls the corresponding generic-text function _tcscmp instead. Depending on how the symbols _MBCS and _UNICODE are defined, _tcscmp maps as follows:

_MBCS defined

_mbscmp

_UNICODE defined

wcscmp

Neither symbol defined

strcmp

Note The symbols _MBCS and _UNICODE are mutually exclusive.

Generic-text function mappings for all of the run-time string-handling routines are detailed in the Run-Time Library Reference. See the category Internationalization.

Similarly, CString member functions are implemented using “generic” data type mappings. To enable both MBCS and Unicode, MFC uses TCHAR for char, LPTSTR for char*, and LPCTSTR for const char*. These result in the correct mappings for either MBCS or Unicode.


Template Topics

Home | Overview | How Do I

This family of articles describes the Microsoft implementation of C++ templates, which is based on the ISO WG21/ANSI X3J16 working papers towards the evolving standard for C++.

For detailed information on template syntax, see template in the Language Quick Reference.

What do you want to know more about?

  • What templates are.

  • When I should use templates.

  • Function templates.

  • Class templates.

  • Templates vs. C/C++ macros.

  • Templates vs. void pointers.

  • Templates and collection classes.

  • Templates and smart pointers.


What Are Templates?

Home | Overview | How Do I

Templates are mechanisms for generating functions and classes based on type parameters (templates are sometimes called “parameterized types”). By using templates, you can design a single class that operates on data of many types, instead of having to create a separate class for each type.

For example, to create a type-safe function that returns the minimum of two parameters without using templates, you would have to write a set of overloaded functions like this:

// min for ints
int min( int a, int b )
    return ( a < b ) ? a : b;

// min for longs
long min( long a, long b )
    return ( a < b ) ? a : b;

// min for chars
char min( char a, char b )
    return ( a < b ) ? a : b;

//etc...

By using templates, you can reduce this duplication to a single function template:

template <class T> T min( T a, T b )
    return ( a < b ) ? a : b;

Templates can significantly reduce source code size and increase code flexibility without reducing type safety.


Working with Function Templates

Home | Overview | How Do I

With function templates, you can specify a set of functions that are based on the same code, but act on different types or classes. For example:

template <class T> void MySwap( T& a, T& b )
{
    T c( a );
    a = b; b = c;
}

This code defines a family of functions that swap their parameters. From this template you can generate functions that will swap not only int and long types, but also user-defined types. MySwap will even swap classes if the class’s copy constructor and assignment operator are properly defined.

In addition, the function template will prevent you from swapping objects of different types, because the compiler knows the types of the a and b parameters at compile time.

You call a function template function as you would a normal function; no special syntax is needed. For example:

int i, j;
char k;
MySwap( i, j );     //OK
MySwap( i, k );     //Error, different types.

Explicit specification of the template arguments for a function template is allowed. For example:

template<class T> void f(T) {...}
void g(char j) {
   f<int>(j);   //generate the specialization f(int)
}

When the template argument is explicitly specified, normal implicit conversions are done to convert the function argument to the type of the corresponding function template parameters. In the above example, the compiler will convert (char j) to type int.

What do you want to know more about?

  • Function template instantiation

  • Function template overrides


Function Template Instantiation

Home | Overview | How Do I

When a function template is first called for each type, the compiler creates an “instantiation,” this is a version of the templated function specialized for the type. This instantiation will be called every time the function is used for the type. If you have several identical instantiations, even in different modules, only one copy of the instantiation will end up in the executable file.

Conversion of function arguments is allowed in function templates for any argument and parameter pair where the parameter does not depend on a template argument. For example:

template<class T> void f(T, int){ };

int i; char c;
f(i, c);

In this example, a conversion of i to type T may cause an error. However, the conversion of (char c) to int is allowed.

Visual C++ 5.0, and later, now supports explicit instantiation of function templates. Previous versions only supported the explicit instantiation of class templates. For example, the following code is now legal:

template<class T> void f(T) {...}

//Instantiate f with the explicitly specified template
//argument ‘int’
//
template void f<int> (int);

//Instantiate f with the deduced template argument 'char'
//
template void f(char);

See Also Explicit Specialization of Function Templates


Explicit Specialization of Function Templates

Home | Overview | How Do I

With a function template, you can define special behavior for a specific type by providing a explicit specialization (override) of the function template for that type. For example:

void MySwap( double a, double b);

This declaration enables you to define a different function for double variables. Like other nontemplated functions, standard type conversions (such as promoting a variable of type float to double) are applied.

Visual C++ 5.0, and later, now supports the new syntax for declaring explicit specializations of function templates. For example:

template<class T> void f(T t) {...};

//Explicit specialization of f with 'char' with the
//template argument explicitly specified:
//
template<> void f<char>(char c){...}

//Explicit specialization of f with 'double' with the
//template argument deduced:
//
template<> void f(double d) {...}

The following form of old syntax is also supported:

//Explicit specialization of f with 'char' with the
//template argument deduced:
//
void f(char) {...}

See Also Function Template Instantiation


Working with Class Templates

Home | Overview | How Do I

You can use class templates to create a family of classes that operate on a type.

template <class T, int i> class TempClass
{
public:
    TempClass( void );
    ~TempClass( void );
    int MemberSet( T a, int b );
private:
    T Tarray[i];
    int arraysize;
};

In this example, the templated class uses two parameters, a type T and an int i. The T parameter can be passed any type, including structures and classes. The i parameter has to be passed an integer constant. Because i is a constant defined at compile time, you can define a member array of size i using a standard array declaration.

What do you want to know more about?

  • Members of template classes

  • Templates for constructors and destructors

  • Class template instantiation

  • Angle bracket placement


Members of Class Templates

Home | Overview | How Do I

Members of classes are defined slightly differently than those of nontemplated classes. Continuing the preceding example:

template <class T, int i>
    int TempClass< T, i >::MemberSet( T a, int b )
    {
        if( ( b >= 0 ) && (b < i) )
        {
           Tarray[b++] = a;
           return sizeof( a );
        }
        else
           return -1;
    }


Templates for Constructors and Destructors

Home | Overview | How Do I

Although constructors and destructors reference the name of the class template twice, the template parameters should be referenced only once in the fully specified name.

template <class T, int i>
TempClass< T, i >::TempClass( void )
{
    TRACE( "TempClass created.\n" );
}

template <class T, int i>
TempClass< T, i >::~TempClass( void )
{
    TRACE( "TempClass destroyed.\n" );
}


Class Template Instantiation

Home | Overview | How Do I

Unlike function templates, when instantiating a class template, you must explicitly instantiate the class by giving the arguments for the class templates. To create an instance of TempClass:

TempClass< float, 6 > test1;       // OK
TempClass< char, items++ > test2;  // Error, second parameter
                                   // must be constant.

No code is generated for a templated class (or function) until it is instantiated. Moreover, member functions are instantiated only if they are called. This can cause problems if you are building a library with templates for other users. See Explicit Instantiation in the C++ Language Reference for more information.

A class template is first specialized and then instantiated by the compiler. The compiler does not instantiate the class template until a reference to a member of this template class is made.

The Visual C++ compiler, in version 5.0 and later, now supports new syntax for explicit specialization of class templates. For example:

template<class T> class X {...};

//Explicit specialization of X with 'int'
//
template<> class X<int> { };

The following form of old syntax is also supported:

//Explicit specialization of X with 'char'
//
class X<char> { };


Angle Bracket Placement

Home | Overview | How Do I

Bad placement of angle brackets (<>) causes many template syntax errors. Make sure that you use proper spacing and parentheses to distinguish angle brackets from operators such as >> and ->. For example:

TempClass< float, a > b ? a : b > test1;

should be rewritten as

TempClass< float, (a > b ? a : b) > test1;

Similarly, pay extra attention when using macros that use angle brackets as template arguments.


When Should You Use Templates?

Home | Overview | How Do I

Templates are often used to:

  • Create a type-safe collection class (for example, a stack) that can operate on data of any type.

  • Add extra type checking for functions that would otherwise take void pointers.

  • Encapsulate groups of operator overrides to modify type behavior (such as smart pointers).

Most of these uses can be implemented without templates; however, templates offer several advantages:

  • Templates are easier to write. You create only one generic version of your class or function instead of manually creating specializations.

  • Templates can be easier to understand, since they can provide a straightforward way of abstracting type information.

  • Templates are type-safe. Because the types that templates act upon are known at compile time, the compiler can perform type checking before errors occur.

What do you want to know more about?

  • Templates vs. C/C++ macros

  • Templates vs. void pointers

  • Templates and collection classes

  • Templates and smart pointers


Templates vs. Macros

Home | Overview | How Do I

In many ways, templates work like preprocessor macros, replacing the templated variable with the given type. However, there are many differences between a macro like this:

#define min(i, j) (((i) < (j)) ? (i) : (j))

and a template:

template<class T> T min (T i, T j) { return ((i < j) ? i : j) }

Here are some problems with the macro:

  • There is no way for the compiler to verify that the macro parameters are of compatible types. The macro is expanded without any special type checking.

  • The i and j parameters are evaluated twice. For example, if either parameter has a postincremented variable, the increment is performed two times.

  • Because macros are expanded by the preprocessor, compiler error messages will refer to the expanded macro, rather than the macro definition itself. Also, the macro will show up in expanded form during debugging.


Templates vs. Void Pointers

Home | Overview | How Do I

Many functions that are now implemented with void pointers can be implemented with templates. Void pointers are often used to allow functions to operate on data of an unknown type. When using void pointers, the compiler cannot distinguish types, so it cannot perform type checking or type-specific behavior such as using type-specific operators, operator overloading, or constructors and destructors.

With templates, you can create functions and classes that operate on typed data. The type looks abstracted in the template definition. However, at compile time the compiler creates a separate version of the function for each specified type. This enables the compiler to treat class and function templates as if they acted on specific types. Templates can also improve coding clarity, because you don’t need to create special cases for complex types such as structures.


Templates and Collection Classes

Home | Overview | How Do I

Templates are a good way of implementing collection classes. Version 4.0 and later of the Microsoft Foundation Class Library uses templates to implement six collection classes: CArray, CMap, CList, CTypedPtrArray, CTypedPtrList, and CTypedPtrMap. For additional information on using and customizing these classes, see Collections Topics.

The MyStack collection is a simple implementation of a stack. The two template parameters, T and i, specify the type of elements in the stack and the maximum number of that item in the stack. The push and pop member functions add and remove items on the stack, with the stack growing from the bottom.

template <class T, int i> class MyStack
{
    T StackBuffer[i];
    int cItems;
public:
    void MyStack( void ) : cItems( i ) {};
    void push( const T item );
    T pop( void );
};

template <class T, int i> void MyStack< T, i >::push( const T item )
{
    if( cItems > 0 )
     StackBuffer[--cItems] = item;
    else
     throw "Stack overflow error.";
    return;
}

template <class T, int i> T MyStack< T, i >::pop( void )
{
    if( cItems < i )
     return StackBuffer[cItems++]
    else

     throw "Stack underflow error.";
}


Templates and Smart Pointers

Home | Overview | How Do I

C++ allows you to create “smart pointer” classes that encapsulate pointers and override pointer operators to add new functionality to pointer operations. Templates allow you to create generic wrappers to encapsulate pointers of almost any type.

The following code outlines a simple reference count garbage collector. The template class Ptr<T> implements a garbage collecting pointer to any class derived from RefCount.

#include <stdio.h>

#define TRACE printf

class RefCount {
    int crefs;
public:
    RefCount(void) { crefs = 0; }
    ~RefCount() { TRACE("goodbye(%d)\n", crefs); }
    void upcount(void) { ++crefs; TRACE("up to %d\n", crefs);}
    void downcount(void)
     {
     if (--crefs == 0)
      {
      delete this;
      }
     else
      TRACE("downto %d\n", crefs);
     }
};

class Sample : public RefCount {
public:
    void doSomething(void) { TRACE("Did something\n");}
};

template <class T> class Ptr {
    T* p;
public:
    Ptr(T* p_) : p(p_) { p->upcount(); }
    ~Ptr(void) { p->downcount(); }
    operator T*(void) { return p; }
    T& operator*(void) { return *p; }
    T* operator->(void) { return p; }
    Ptr& operator=(Ptr<T> &p_)
        {return operator=((T *) p_);}
    Ptr& operator=(T* p_) {
        p->downcount(); p = p_; p->upcount(); return *this;
    }
};

int main() {
    Ptr<Sample> p  = new Sample; // sample #1
    Ptr<Sample> p2 = new Sample; // sample #2
    p = p2; // #1 will have 0 crefs, so it is destroyed;
            // #2 will have 2 crefs.
    p->doSomething();
    return 0;
    // As p2 and p go out of scope, their destructors call
    // downcount. The cref variable of #2 goes to 0, so #2 is
    // destroyed
}

Classes RefCount and Ptr<T> together provide a simple garbage collection solution for any class that can afford the int per instance overhead to inherit from RefCount. Note that the primary benefit of using a parametric class like Ptr<T> instead of a more generic class like Ptr is that the former is completely type-safe. The preceding code ensures that a Ptr<T> can be used almost anywhere a T* is used; in contrast, a generic Ptr would only provide implicit conversions to void*.

For example, consider a class used to create and manipulate garbage collected files, symbols, strings, and so forth. From the class template Ptr<T>, the compiler will create template classes Ptr<File>, Ptr<Symbol>, Ptr<String>, and so on, and their member functions: Ptr<File>::~Ptr(), Ptr<File>::operator File*(), Ptr<String>::~Ptr(), Ptr<String>::operator String*(), and so on.


Unicode Topics

Home | Overview | How Do I | Sample

On Windows NT platforms, MFC supports the Unicode standard for encoding wide characters. Unicode is not presently supported on Windows 95.

Note The Unicode versions of the MFC libraries are not copied to your hard drive unless you select them during a Custom installation. They are not copied during other types of installation. If you attempt to build or run an MFC Unicode application without the MFC Unicode files, you may get errors.

To copy the files to your hard drive, rerun Setup, choose Custom installation, clear all other components except "Microsoft Foundation Class Libraries," click the Details button, and select both "Static Library for Unicode" and "Shared Library for Unicode."

The Unicode versions of the MFC libraries are described below:

Static Link Libraries

Release | Debug | Description
UAFXCW.lib, .pdb | UAFXCWD.lib, .pdb | Unicode MFC static link library

Dynamic Link Libraries

Release | Debug | Description
MFC42U.lib, .dbg, def, .dll, .map, .pdb, .prf | MFC42UD.lib, .def, .dll, .map, .pdb | Unicode MFC import library (see notes below for explanation of file extensions)
 | MFCD42UD.lib, .def, .dll, .map, .pdb | Unicode MFC import library for database
 | MFCN42UD.lib, .def, .dll, .map, .pdb | Unicode MFC import library for network (sockets)
 | MFCO42UD.lib, .def, .dll, .map, .pdb | Unicode MFC DLL for Active technologies
MFCS42U.lib, .pdb | MFCS42UD.lib, .pdb | Unicode MFC import library containing code that must be statically linked in an application or DLL

File types:

  • Import library files have the extension (.lib).

  • Dynamic link library files have the extension (.dll).

  • Module definition (.def) files are text files that contain statements for defining an .exe or .dll.

  • Map (.map) files are text files that contain information that the linker uses when linking a program.

  • Library (.lib) files are used in conjunction with the DLL versions of MFC. These files contain code that must be statically linked in the application or DLL.

  • Program database (.pdb) files contain debugging and project state information.

  • Debug (.dbg) files contain information (COFF FPO, and CodeView) that the Visual C++ Debugger uses.

For detailed information on naming conventions, see Naming Conventions for MFC DLLs and Library Naming Conventions.

For information on using Unicode with MFC, see International Programming Topics and Strings: Unicode and Multibyte Character Set (MBCS) Support.


Windows Sockets Topics

Home | Overview | How Do I | Sample

This family of articles covers the MFC implementation of Windows Sockets. For background information on what the Windows Sockets API is, see Windows Sockets: Background.

What do you want to know more about?

  • Windows Sockets in general

  • Windows sockets in MFC

  • Definition of a socket

  • Uses for sockets

  • Sockets programming models

  • MFC socket samples and a simple example

  • Sequence of socket operations

  • Class CSocket: sockets with archives

  • Class CAsyncSocket: wrapping the sockets API

  • Deriving from socket classes

  • Socket notifications

  • Blocking

  • Byte ordering

  • Ports and socket addresses

  • Windows Sockets DLLs


Windows Sockets in MFC

Home | Overview | How Do I | Sample

MFC supplies two models for writing network communications programs with Windows Sockets, embodied in two MFC classes. This article describes these models and further details MFC sockets support. A “socket” is an endpoint of communication — an object through which your application communicates with other Windows Sockets applications across a network.

This article describes:

  • Sockets programming models.

  • MFC socket samples and Windows Sockets DLLs.

  • Windows sockets articles.

For background information on Windows Sockets, including a detailed explanation of the socket concept, see the article Windows Sockets: Background.

Sockets Programming Models

The two MFC Windows Sockets programming models are supported by the following classes:

  • CAsyncSocket

    This class encapsulates the Windows Sockets API. CAsyncSocket is for programmers who know network programming and want the flexibility of programming directly to the sockets API but also want the convenience of callback functions for notification of network events. Other than packaging sockets in object-oriented form for use in C++, the only additional abstraction this class supplies is converting certain socket-related Windows messages into callbacks. (See the article Windows Sockets: Socket Notifications.)

  • CSocket

    This class, derived from CAsyncSocket, supplies a higher-level abstraction for working with sockets via an MFC CArchive object. Using a socket with an archive greatly resembles using MFC’s file serialization protocol. This makes it easier to use than the CAsyncSocket model. CSocket inherits many member functions from CAsyncSocket that encapsulate Windows Sockets APIs; you will have to use some of these functions and understand sockets programming generally. But CSocket manages many aspects of the communication that you would have to do yourself using either the raw API or class CAsyncSocket. Most important, CSocket provides blocking (with background processing of Windows messages), which is essential to the synchronous operation of CArchive.

Creating and using CSocket and CAsyncSocket objects is described in the articles Windows Sockets: Using Sockets with Archives and Windows Sockets: Using Class CAsyncSocket.

MFC Socket Samples and Windows Sockets DLLs

Visual C++ supplies the CHATTER and CHATSRVR sample applications to illustrate the client/server model, which is the most common model. CHATTER is the client; CHATSRVR is the server. These samples make good templates for writing your own clients and servers. You can access the source code for the MFC Advanced Concepts samples CHATTER and CHATSRVR.

The Microsoft Windows NT operating system supplies the Windows Sockets dynamic link libraries (DLLs). Visual C++ supplies the appropriate header files and libraries and the Windows Sockets specification. The specification is available in the Win32 SDK.

Note Under Windows NT, Windows Sockets support for 16-bit applications is based on WINSOCK.DLL. For 32-bit applications, the support is in WSOCK32.DLL. The APIs provided are identical except that the 32-bit versions have parameters widened to 32 bits. Under Win32, thread safety is supplied.

ClassWizard does not support creating classes derived from the MFC Windows Sockets classes.

Windows Sockets Articles

For detailed information about Windows Sockets and their implementation in MFC, see the following articles:

  • Windows Sockets: Background

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets

  • Windows Sockets: Using Sockets with Archives

  • Windows Sockets: Sequence of Operations

  • Windows Sockets: Example of Sockets Using Archives

  • Windows Sockets: How Sockets with Archives Work

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Deriving from Socket Classes

  • Windows Sockets: Socket Notifications

  • Windows Sockets: Blocking

  • Windows Sockets: Byte Ordering

  • Windows Sockets: Converting Strings

  • Windows Sockets: Ports and Socket Addresses


Windows Sockets: Background

Home | Overview | How Do I | Sample

This article explains the nature and purpose of Windows Sockets. The article also:

  • Defines the term “socket”.

  • Describes the SOCKET handle data type.

  • Describes uses for sockets.

The Windows Sockets specification defines a binary-compatible network programming interface for Microsoft Windows. Windows Sockets are based on the UNIX® sockets implementation in the Berkeley Software Distribution (BSD, release 4.3) from the University of California at Berkeley. The specification includes both BSD-style socket routines and extensions specific to Windows. Using Windows Sockets permits your application to communicate across any network that conforms to the Windows Sockets API. On Win32, Windows Sockets provide for thread safety.

Many network software vendors support Windows Sockets under network protocols including Transmission Control Protocol/Internet Protocol (TCP/IP), Xerox® Network System (XNS), Digital Equipment Corporation’s DECNet™ protocol, Novell® Corporation’s Internet Packet Exchange/Sequenced Packed Exchange (IPX/SPX), and others. Although the present Windows Sockets specification defines the sockets abstraction for TCP/IP, any network protocol can comply with Windows Sockets by supplying its own version of the dynamic link library (DLL) that implements Windows Sockets. Examples of commercial applications written with Windows Sockets include X Window servers, terminal emulators, and electronic mail systems.

Note Keep in mind that the purpose of Windows Sockets is to abstract away the underlying network so you don’t have to be knowledgeable about that network and so your application can run on any network that supports sockets. Consequently, this documentation doesn’t discuss the details of network protocols.

The Microsoft Foundation Class Library (MFC) supports programming with the Windows Sockets API by supplying two classes. One of these classes, CSocket, provides a high level of abstraction to simplify your network communications programming. For more information about MFC socket support, see Windows Sockets for Network Programming: Overview.

The Windows Sockets specification, Windows Sockets: An Open Interface for Network Computing Under Microsoft Windows, now at version 1.1, was developed as an open networking standard by a large group of individuals and corporations in the TCP/IP community and is freely available for use. The sockets programming model supports one “communication domain” currently, using the Internet Protocol Suite. The specification is available in the Win32 SDK.

Tip Because sockets use the Internet Protocol Suite, they are the preferred route for applications that support Internet communications on the “information highway.”

Definition of a Socket

A socket is a communication endpoint — an object through which a Windows Sockets application sends or receives packets of data across a network. A socket has a type and is associated with a running process, and it may have a name. Currently, sockets generally exchange data only with other sockets in the same “communication domain,” which uses the Internet Protocol Suite.

Both kinds of sockets are bi-directional: they are data flows that can be communicated in both directions simultaneously (full-duplex).

Two socket types are available:

  • Stream sockets

    Stream sockets provide for a data flow without record boundaries — a stream of bytes. Streams are guaranteed to be delivered and to be correctly sequenced and unduplicated.

  • Datagram sockets

    Datagram sockets support a record-oriented data flow that is not guaranteed to be delivered and may not be sequenced as sent or unduplicated.

“Sequenced” means that packets are delivered in the order sent. “Unduplicated” means that you get a particular packet only once.

Note Under some network protocols, such as XNS, streams can be record-oriented — streams of records rather than streams of bytes. Under the more common TCP/IP protocol, however, streams are byte streams. Windows Sockets provides a level of abstraction independent of the underlying protocol.

For information about these types and which kind of socket to use in which situations, see the articles Windows Sockets: Stream Sockets and Windows Sockets: Datagram Sockets.

The SOCKET Data Type

Each MFC socket object encapsulates a handle to a Windows Sockets object. The data type of this handle is SOCKET. A SOCKET handle is analogous to the HWND for a window. MFC socket classes provide operations on the encapsulated handle.

The SOCKET data type is described in detail in the Win32 SDK. See the topic Socket Data Type and Error Values under Windows Sockets.

Uses for Sockets

Sockets are highly useful in at least three communications contexts:

  • Client/Server models

  • Peer-to-peer scenarios, such as chat applications

  • Making remote procedure calls (RPC) by having the receiving application interpret a message as a function call

Tip The ideal case for using MFC sockets is when you’re writing both ends of the communication: using MFC at both ends. For more information on this topic, including how to manage the case when you’re communicating with non-MFC applications, see the article Windows Sockets: Byte Ordering.

For more information, see Windows Sockets Specification: ntohs, ntohl, htons, htonl.

What do you want to know more about?

  • Windows Sockets: Using Sockets with Archives

  • Windows Sockets: Example of Sockets Using Archives

  • Windows Sockets: Using Class CAsyncSocket


Windows Sockets: Stream Sockets

Home | Overview | How Do I | Sample

This article describes stream sockets, one of the two Windows Socket types available. (The other type is the datagram socket.)

Stream sockets provide for a data flow without record boundaries — a stream of bytes that can be bi-directional (the application is full-duplex: it can both transmit and receive through the socket). Streams can be relied upon to deliver sequenced, unduplicated data. (“Sequenced” means that packets are delivered in the order sent. “Unduplicated” means that you get a particular packet only once.) Receipt of stream messages is guaranteed, and streams are well-suited to handling large amounts of data.

The network transport layer may break up or group data into packets of reasonable size. The CSocket class will handle the packing and unpacking for you.

Streams are based on explicit connections: socket A requests a connection to socket B; socket B accepts or rejects the connection request.

A telephone call provides a good analogy for a stream: under normal circumstances, the receiving party hears what you say in the order that you say it, without duplication or loss. Stream sockets are appropriate, for example, for implementations such as the File Transfer Protocol (FTP), which facilitates transferring ASCII or binary files of arbitrary size.

Stream sockets are preferable to datagram sockets when the data must be guaranteed to arrive and when data size is large. For more information about stream sockets, see the Windows Sockets specification. The specification is available in the Win32 SDK.

The MFC Advanced Concepts samples CHATTER and CHATSRVR use stream sockets. These samples might have been designed to use a datagram socket for broadcasting to all receiving sockets on the network. The present design is superior because (a) the broadcast model is subject to network flood (or “storm”) problems, (b) the client-server model adopted subsequently is more efficient, (c) the stream model supplies reliable data transfer, where the datagram model does not, and (d) the final model takes advantage of the ability to communicate between Unicode and ANSI socket applications that class CArchive lends to class CSocket.

Important If you use class CSocket, you must use a stream. An MFC assertion fails if you specify the socket type as SOCK_DGRAM.

See Also Windows Sockets: Background


Windows Sockets: Datagram Sockets

Home | Overview | How Do I | Sample

This article describes datagram sockets, one of the two Windows Socket types available. (The other type is the stream socket.)

Datagram sockets support a bi-directional data flow that is not guaranteed to be sequenced or unduplicated. Datagrams also are not guaranteed to be reliable; they can fail to arrive. Datagram data may arrive out of order and possibly duplicated, but record boundaries in the data are preserved, as long as the records are smaller than the receiver’s internal size limit. You are responsible for managing sequencing and reliability. (Reliability tends to be good on local area networks (LANs) but less so on wide area networks (WANs), such as the Internet.)

Datagrams are “connectionless” — no explicit connection is established; you send a datagram message to a specified socket and you can receive messages from a specified socket.

An example of a datagram socket is an application that keeps system clocks on the network synchronized. This illustrates an additional capability of datagram sockets in at least some settings: broadcasting messages to a large number of network addresses.

Datagram sockets are better than stream sockets for record-oriented data. For more information about datagram sockets, see the Windows Sockets specification. The specification is available in the Win32 SDK.

See Also Windows Sockets: Background


Windows Sockets: Using Sockets with Archives

Home | Overview | How Do I | Sample

This article describes the CSocket programming model. Class CSocket supplies socket support at a higher level of abstraction than does class CAsyncSocket. CSocket uses a version of the MFC serialization protocol to pass data to and from a socket object via an MFC CArchive object. CSocket provides blocking (while managing background processing of Windows messages) and gives you access to CArchive, which manages many aspects of the communication that you would have to do yourself using either the raw API or class CAsyncSocket.

Tip You can use class CSocket by itself, as a more convenient version of CAsyncSocket, but the simplest programming model is to use CSocket with a CArchive object.

For additional information about how the implementation of sockets with archives works, see the article Windows Sockets: How Sockets with Archives Work. For example code, see the articles Windows Sockets: Sequence of Operations and Windows Sockets: Example of Sockets Using Archives. For information about some of the functionality you can gain by deriving your own classes from the sockets classes, see the article Windows Sockets: Deriving from Socket Classes.

Caution If you are writing an MFC client program to communicate with established (non-MFC) servers, don’t send C++ objects via the archive. Unless the server is an MFC application that understands the kinds of objects you want to send, it won’t be able to receive and deserialize your objects. For related material on the subject of communicating with non-MFC applications, also see the article Windows Sockets: Byte Ordering.

The CSocket Programming Model

Using a CSocket object involves creating and associating together several MFC class objects. In the general procedure below, each step is taken by both the server socket and the client socket, except for step 3, in which each socket type requires a different action.

Tip At run time, the server application usually starts first in order to be ready and “listening” when the client application seeks a connection. If the server is not ready when the client tries to connect, you typically require the user application to try connecting again later.

To set up communication between a server socket and a client socket

  1. Construct a CSocket object.

  2. Use the object to create the underlying SOCKET handle.

    For a CSocket client object, you should normally use the default parameters to Create, unless you need a datagram socket. For a CSocket server object, you must specify a port in the Create call.

    Note CArchive doesn’t work with datagram sockets. If you want to use CSocket for a datagram socket, you must use the class as you would CAsyncSocket — without an archive. Because datagrams are unreliable (not guaranteed to arrive and may be repeated or out of sequence), they aren’t compatible with serialization via an archive. You expect a serialization operation to complete reliably and in sequence. If you try to use CSocket with a CArchive object for a datagram, an MFC assertion fails.

  3. If the socket is a client, call CAsyncSocket::Connect to connect the socket object to a server socket.

    -or-

    If the socket is a server, call CAsyncSocket::Listen to begin listening for connect attempts from a client. Upon receiving a connection request, accept it by calling CAsyncSocket::Accept.

    Note The Accept member function takes a reference to a new, empty CSocket object as its parameter. You must construct this object before you call Accept. Keep in mind that if this socket object goes out of scope, the connection closes. Do not call Create for this new socket object.

  4. Create a CSocketFile object, associating the CSocket object with it.

  5. Create a CArchive object for either loading (receiving) or storing (sending) data. The archive is associated with the CSocketFile object.

    Keep in mind that CArchive doesn’t work with datagram sockets.

  6. Use the CArchive object to pass data between the client and server sockets.

    Keep in mind that a given CArchive object moves data in one direction only: either for loading (receiving) or storing (sending). In some cases, you’ll use two CArchive objects, one for sending data, the other for receiving acknowledgments.

    After accepting a connection and setting up the archive, you can perform such tasks as validating passwords.

  7. Destroy the archive, socket file, and socket objects.

Note Class CArchive supplies the IsBufferEmpty member function specifically for use with class CSocket. If the buffer contains multiple data messages, for example, you need to loop until all of them are read and the buffer is cleared. Otherwise, your next notification that there is data to be received may be indefinitely delayed. Use IsBufferEmpty to assure that you retrieve all data. For examples of using IsBufferEmpty, see the CHATSRVR sample application. For source code and information about MFC samples, see MFC Samples.

The article Windows Sockets: Sequence of Operations illustrates both sides of this process with example code.

What do you want to know more about?

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets

See Also CSocket::Create


Windows Sockets: Sequence of Operations

Home | Overview | How Do I | Sample

This article illustrates, side by side, the sequence of operations for a server socket and a client socket. Because the sockets use CArchive objects, they are necessarily stream sockets.

Sequence of Operations for a Stream Socket Communication

Up to the point of constructing a CSocketFile object, the following sequence is accurate (with a few parameter differences) for both CAsyncSocket and CSocket. From that point on, the sequence is strictly for CSocket. The following table illustrates the sequence of operations for setting up communication between a client and a server.

Setting Up Communication Between a Server and a Client

Server Client
// construct a socket

CSocket sockSrvr;

 // construct a socket

CSocket sockClient;
// create the SOCKET

sockSrvr.Create(nPort);1,2

 // create the SOCKET

sockClient.Create( );2
// start listening

sockSrvr.Listen( );
// seek a connection

sockClient.Connect(strAddr, nPort);3,4
// construct a new, empty socket

CSocket sockRecv;

// accept connection

sockSrvr.Accept( sockRecv ); 5
// construct file object

CSocketFile file(&sockRecv);

 // construct file object

CSocketFile file(&sockClient);
// construct an archive

CArchive arIn(&file,
CArchive::load);

-or-

CArchive arOut(&file,
CArchive::store);

– or Both –

// construct an archive

CArchive arIn(&file,
CArchive::load);

-or-

CArchive arOut(&file,
CArchive::store);

– or Both –

// use the archive to pass data:

arIn >> dwValue;

-or-

arOut << dwValue;6

 // use the archive to pass data:

arIn >> dwValue;

-or-

arOut << dwValue;6

1. Where nPort is a port number. See Windows Sockets: Ports and Socket Addresses for details about ports.

2. The server must always specify a port so clients can connect. The Create call sometimes also specifies an address. On the client side, use the default parameters, which ask MFC to use any available port.

3. Where nPort is a port number and strAddr is a machine address or an Internet Protocol (IP) address.

4. Machine addresses can take several forms: “ftp.microsoft.com”, “ucsd.edu”. IP addresses use the “dotted number” form “127.54.67.32”. The Connect function checks to see if the address is a dotted number (although it doesn’t check to ensure the number is a valid machine on the network). If not, Connect assumes a machine name of one of the other forms.

5. When you call Accept on the server side, you pass a reference to a new socket object. You must construct this object first, but do not call Create for it. Keep in mind that if this socket object goes out of scope, the connection closes. MFC connects the new object to a SOCKET handle. You can construct the socket on the stack, as shown, or on the heap.

6. The archive and the socket file are closed when they go out of scope. The socket object’s destructor also calls the Close member function for the socket object when the object goes out of scope or is deleted.

Additional Notes About the Sequence

The sequence of calls shown in the preceding table is for a stream socket. Datagram sockets, which are connectionless, don’t require the CAsyncSocket::Connect, Listen, and Accept calls (although you can optionally use Connect). Instead, if you’re using class CAsyncSocket, datagram sockets use the CAsyncSocket::SendTo and ReceiveFrom member functions. (If you use Connect with a datagram socket, you use Send and Receive.) Because CArchive doesn’t work with datagrams, don’t use CSocket with an archive if the socket is a datagram.

CSocketFile doesn’t support all of CFile’s functionality; CFile members such as Seek, which make no sense for a socket communication, are unavailable. Because of this, some default MFC Serialize functions aren’t compatible with CSocketFile. This is particularly true of the CEditView class. You should not try to serialize CEditView data through a CArchive object attached to a CSocketFile object using CEditView::SerializeRaw; use CEditView::Serialize instead (not documented). The SerializeRaw function expects the file object to have functions, such as Seek, that CSocketFile does not support.

What do you want to know more about?

  • Windows Sockets: Using Sockets with Archives

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Ports and Socket Addresses

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets

See Also CSocket, CAsyncSocket::Create, CAsyncSocket::Close


Windows Sockets: Example of Sockets Using Archives

Home | Overview | How Do I | Sample

This article presents an example of using class CSocket. The example employs CArchive objects to serialize data via a socket. Note that this is not document serialization to or from a file.

The following example illustrates how you use the archive to send and receive data via CSocket objects. The example is designed so that two instances of the application (on the same machine or on different machines on the network) exchange data. One instance sends data, which the other instance receives and acknowledges. Either application can initiate an exchange — either can act as server or as client to the other application. The following function is defined in the application’s view class:

void CBlabberView::PacketSerialize(long nPackets, CArchive& arData,
                                    CArchive& arAck)
{
    if (arData.IsStoring())
    {
        CString strText;

        for(int p = 0; p < nPackets; p++)
        {
            BYTE bValue = (BYTE)(rand()%256);
            WORD nCopies = (WORD)(rand()%32000);

            // send header information
            arData << bValue << nCopies;
            for(int c = 0; c < nCopies; c++)
            {
                // send data
                arData << bValue;
            }

            Text.Format("Received Packet %d of %d
                (Value=%d,Copies=%d)",p,nPackets,(int)bValue,nCopies);

            // send receipt string
            arData << strText;
            arData.Flush();

            // receive acknowledgment
            arAck >> strText;
            // display it
            DisplayMessage(strText);
        }
    }
    else
    {
        CString strText;
        BYTE bCheck;
        WORD nCopies;

        for(int p = 0; p < nPackets; p++)
        {
            // receive header information
            arData >> bCheck >> nCopies;
            for(int c = 0; c < nCopies; c++)
            {
                // receive data
                arData >> bValue;
                if (nCheck != bValue)
                    AfxMessageBox("Packet Failure");
            }
        }

        // receive receipt string and display it
        arData >> strText;
        DisplayMessage(strText);

        Text.Format("Sent Packet %d of %d
            (Value=%d,Copies=%d)",p,nPackets,(int)bValue,nCopies);

        // send acknowledgment
        arAck << strText;
        arAck.Flush();
    }
}

The most important thing about this example is that its structure parallels that of an MFC Serialize function. The PacketSerialize member function consists of an if statement with an else clause. The function receives two CArchive references as parameters: arData and arAck. If the arData archive object is set for storing (sending), the if branch executes; otherwise, if arData is set for loading (receiving) the function takes the else branch. For more information about serialization in MFC, see the article Serialization.

Note The arAck archive object is assumed to be the opposite of arData. If arData is for sending, arAck receives, and vice versa.

For sending, the example function loops for a specified number of times, each time generating some random data for demonstration purposes. Your application would obtain real data from some source, such as a file. The arData archive’s insertion operator (<<) is used to send a stream of three consecutive chunks of data:

  • A “header” that specifies the nature of the data (in this case, the value of the bValue variable and how many copies will be sent).

    Both items are generated randomly for this example.

  • The specified number of copies of the data.

    The inner for loop sends bValue the specified number of times.

  • A string called strText that the receiver displays to its user.

For receiving, the function operates similarly, except that it uses the archive’s extraction operator (>>) to get data from the archive. The receiving application verifies the data it receives, displays the final “Received” message, then sends back a message that says “Sent” for the sending application to display.

Don’t be confused by the word “Received” in the message sent in the strText variable. In this communications model, it’s for display at the other end of the communication, so it specifies to the receiving user that a certain number of packets of data have been received. The receiver replies with a similar string that says “Sent” — for display on the original sender’s screen. Receipt of both strings indicates that successful communication has occurred.

Caution If you are writing an MFC client program to communicate with established (non-MFC) servers, don’t send C++ objects via the archive. Unless the server is an MFC application that understands the kinds of objects you want to send, it won’t be able to receive and deserialize your objects. An example in the article Windows Sockets: Byte Ordering shows a communication of this type.

For more information, see Windows Sockets Specification: htonl, htons, ntohl, ntohs.

What do you want to know more about?

  • Windows Sockets: Deriving from Socket Classes

  • Windows Sockets: How Sockets with Archives Work

  • Windows Sockets: Background

  • Windows Sockets for Network Programming: Overview

See Also CArchive::IsStoring, CArchive::operator<<, CArchive::operator>>, CString::Format, CArchive::Flush, CObject::Serialize


Windows Sockets: How Sockets with Archives Work

Home | Overview | How Do I | Sample

This article explains how a CSocket object, a CSocketFile object, and a CArchive object are combined to simplify sending and receiving data via a Windows socket.

The article Windows Sockets: Example of Sockets Using Archives presents the PacketSerialize function. The archive object in the PacketSerialize example works much like an archive object passed to an MFC Serialize function. The essential difference is that for sockets, the archive is attached not to a standard CFile object (typically associated with a disk file) but to a CSocketFile object. Rather than connecting to a disk file, the CSocketFile object connects to a CSocket object.

A CArchive object manages a buffer. When the buffer of a storing (sending) archive is full, an associated CFile object writes out the buffer’s contents. Flushing the buffer of an archive attached to a socket is equivalent to sending a message. When the buffer of a loading (receiving) archive is full, the CFile object stops reading until the buffer is available again.

Class CSocketFile derives from CFile, but it doesn’t support CFile member functions such as the positioning functions (Seek, GetLength, SetLength, and so on), the locking functions (LockRange, UnlockRange), or the GetPosition function. All the CSocketFile object must do is write or read sequences of bytes to or from the associated CSocket object. Because a file is not involved, operations such as Seek and GetPosition make no sense. CSocketFile is derived from CFile, so it would normally inherit all of these member functions. To prevent this, the unsupported CFile member functions are overridden in CSocketFile to throw a CNotSupportedException.

The CSocketFile object calls member functions of its CSocket object to send or receive data.

The following figure shows the relationships among these objects on both sides of the communication.

CArchive, CSocketFile, and CSocket

The purpose of this apparent complexity is to shield you from the necessity of managing the details of the socket yourself. You simply create the socket, the file, and the archive, then begin sending or receiving data by inserting it to the archive or extracting it from the archive. CArchive, CSocketFile, and CSocket manage the details behind the scenes.

A CSocket object is actually a two-state object: sometimes asynchronous (the usual state) and sometimes synchronous. In its asynchronous state, a socket can receive asynchronous notifications from the framework. But during an operation such as receiving or sending data the socket becomes synchronous. This means the socket will receive no further asynchronous notifications until the synchronous operation has completed. Because it switches modes, you can, for example, do something like the following:

CMySocket::OnReceive( )
{
    // ...
    ar >> str;
    // ...
}

If CSocket were not implemented as a two-state object, it might be possible to receive additional notifications for the same kind of event while you were processing a previous notification. For example, you might get an OnReceive notification while processing an OnReceive. In the code fragment above, extracting str from the archive might lead to recursion. By switching states, CSocket prevents recursion by preventing additional notifications. The general rule is: no notifications within notifications.

The CHATTER and CHATSRVR sample applications illustrate such usage. For source code and information about MFC samples, see MFC Samples.

Note A CSocketFile can also be used as a (limited) file without a CArchive object. By default, the CSocketFile constructor’s bArchiveCompatible parameter is TRUE. This specifies that the file object is for use with an archive. To use the file object without an archive, pass FALSE in the bArchiveCompatible parameter.

In its “archive compatible” mode, a CSocketFile object provides better performance and reduces the danger of a “deadlock.” A deadlock occurs when both the sending and receiving sockets are waiting on each other, or waiting for a common resource. This situation might occur if the CArchive object worked with the CSocketFile the way it does with a CFile object. With CFile, the archive can assume that if it receives fewer bytes than it requested, the end of file has been reached. With CSocketFile, however, data is message based; the buffer can contain multiple messages, so receiving fewer than the number of bytes requested does not imply end of file. The application doesn’t block in this case as it might with CFile, and it can continue reading messages from the buffer until the buffer is empty. The IsBufferEmpty function in CArchive is useful for monitoring the state of the archive’s buffer in such a case.

What do you want to know more about?

  • Windows Sockets: Using Sockets with Archives

See Also CObject::Serialize


Windows Sockets: Using Class CAsyncSocket

Home | Overview | How Do I | Sample

This article explains how to use class CAsyncSocket. Be aware that this class encapsulates the Windows Sockets API at a very low level. CAsyncSocket is for use by programmers who know network communications in detail but want the convenience of callbacks for notification of network events. Based on this assumption, this article provides only basic instruction. You should probably consider using CAsyncSocket if you want Windows Sockets’ ease of dealing with multiple network protocols in an MFC application but don’t want to sacrifice flexibility. You might also feel that you can get better efficiency by programming the communications more directly yourself than you could using the more general alternative model of class CSocket.

CAsyncSocket is documented in the Class Library Reference. Visual C++ also supplies the Windows Sockets specification, located in the Win32 SDK. The details are left to you. Visual C++ does not supply a sample application for CAsyncSocket.

If you aren’t highly knowledgeable about network communications and want a simple solution that shields you from most of the details, use class CSocket with a CArchive object. See the article Windows Sockets: Using Sockets with Archives.

This article covers:

  • Creating and using a CAsyncSocket object.

  • Your responsibilities with CAsyncSocket.

Creating and Using a CAsyncSocket Object

To use CAsyncSocket

  1. Construct a CAsyncSocket object and use the object to create the underlying SOCKET handle.

    Creation of a socket follows the MFC pattern of two-stage construction.

    For example:

    CAsyncSocket sock;
sock.Create( );    // Use the default parameters

    -or-

    CAsyncSocket* pSocket = new CAsyncSocket;
int nPort = 27;
pSocket->Create( nPort, SOCK_DGRAM );

    The first constructor above creates a CAsyncSocket object on the stack. The second constructor creates a CAsyncSocket on the heap. The first Create call above uses the default parameters to create a stream socket. The second Create call creates a datagram socket with a specified port and address. (You can use either Create version with either construction method.)

    The parameters to Create are:

    • A “port”: a short integer.

      For a server socket, you must specify a port. For a client socket, you’ll typically accept the default value for this parameter, which lets Windows Sockets select a port.

    • A socket type: SOCK_STREAM (the default) or SOCK_DGRAM.

    • A socket “address,” such as “ftp.microsoft.com” or “128.56.22.8”.

      This is your Internet Protocol (IP) address on the network. You’ll probably always rely on the default value for this parameter.

    The terms “port” and “socket address” are explained in the article Windows Sockets: Ports and Socket Addresses.

  2. If the socket is a client, connect the socket object to a server socket, using CAsyncSocket::Connect.

    -or-

    If the socket is a server, set the socket to begin listening (with CAsyncSocket::Listen) for connect attempts from a client. Upon receiving a connection request, accept it with CAsyncSocket::Accept.

    After accepting a connection, you can perform such tasks as validating passwords.

    Note The Accept member function takes a reference to a new, empty CSocket object as its parameter. You must construct this object before you call Accept. Keep in mind that if this socket object goes out of scope, the connection closes. Do not call Create for this new socket object. For an example, see the article Windows Sockets: Sequence of Operations.

  3. Carry out communications with other sockets by calling the CAsyncSocket object’s member functions that encapsulate the Windows Sockets API functions.

    See the Windows Sockets specification and class CAsyncSocket in the Class Library Reference.

  4. Destroy the CAsyncSocket object.

    If you created the socket object on the stack, its destructor is called when the containing function goes out of scope. If you created the socket object on the heap, using the new operator, you are responsible for using the delete operator to destroy the object.

    The destructor calls the object’s Close member function before destroying the object.

For an example of this sequence in code (actually for a CSocket object), see the article Windows Sockets: Sequence of Operations.

Your Responsibilities with CAsyncSocket

When you create an object of class CAsyncSocket, the object encapsulates a Windows SOCKET handle and supplies operations on that handle. When you use CAsyncSocket, you must deal with all of the issues you might face if using the API directly. For example:

  • “Blocking” scenarios

  • Byte order differences between the sending and receiving machines

  • Converting between Unicode and multibyte character set (MBCS) strings

For definitions of these terms and additional information, see the articles Windows Sockets: Blocking, Windows Sockets: Byte Ordering, Windows Sockets: Converting Strings.

Despite these issues, class CAsycnSocket may be the right choice for you if your application requires all the flexibility and control you can get. If not, you should consider using class CSocket instead. CSocket hides a lot of detail from you: it pumps Windows messages during blocking calls and gives you access to CArchive, which manages byte order differences and string conversion for you.

What do you want to know more about?

  • Windows Sockets: Background

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets


Windows Sockets: Deriving from Socket Classes

Home | Overview | How Do I | Sample

This article describes some of the functionality you can gain by deriving your own class from one of the socket classes.

You can derive your own socket classes from either CAsyncSocket or CSocket to add your own functionality. In particular, these classes supply a number of virtual member functions that you can override. These functions include OnReceive, OnSend, OnAccept, OnConnect, and OnClose. You can override the functions in your derived socket class to take advantage of the notifications they provide when network events occur. The framework calls these notification callback functions to notify you of important socket events, such as the receipt of data that you can begin reading. For more information about notification functions, see Windows Sockets: Socket Notifications. For an illustration of overriding the notification functions, see the CHATTER and CHATSRVR sample applications.

Additionally, class CSocket supplies the OnMessagePending member function (an advanced overridable). MFC calls this function while the socket is pumping Windows-based messages. You can override OnMessagePending to look for particular messages from Windows and respond to them.

The default version of OnMessagePending supplied in class CSocket examines the message queue for WM_PAINT messages while waiting for a blocking call to complete. It dispatches paint messages in order to improve display quality. Aside from doing something useful, this illustrates one way you might override the function yourself. As another example, consider using OnMessagePending for the following task. Suppose you display a modeless dialog box while waiting for a network transaction to complete. The dialog box contains a Cancel button that the user can use to cancel blocking transactions that take too long. Your OnMessagePending override might pump messages related to this modeless dialog box.

In your OnMessagePending override, return either TRUE or the return from a call to the base-class version of OnMessagePending. Call the base-class version if it performs work that you still want done.

What do you want to know more about?

  • Windows Sockets: Using Sockets with Archives

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Blocking

  • Windows Sockets: Byte Ordering

  • Windows Sockets: Converting Strings


Windows Sockets: Socket Notifications

Home | Overview | How Do I | Sample

This article describes the notification functions in the socket classes. These member functions are callback functions that the framework calls to notify your socket object of important events. The notification functions are:

  • OnReceive: Notifies this socket that there is data in the buffer for it to retrieve by calling Receive.

  • OnSend: Notifies this socket that it can now send data by calling Send.

  • OnAccept: Notifies this listening socket that it can accept pending connection requests by calling Accept.

  • OnConnect: Notifies this connecting socket that its connection attempt completed: perhaps successfully or perhaps in error.

  • OnClose: Notifies this socket that the socket it is connected to has closed.

Note An additional notification function is OnOutOfBandData. This notification tells the receiving socket that the sending socket has “out-of-band” data to send. Out-of-band data is a logically independent channel associated with each pair of connected stream sockets. The out-of-band channel is typically used to send “urgent” data. MFC supports out-of-band data. Advanced users working with class CAsyncSocket might need to use the out-of-band channel, but users of class CSocket are discouraged from using it. The easier way is to create a second socket for passing such data. For more information about out-of-band data, see the Windows Sockets specification, available in the Win32 SDK.

If you derive from class CAsyncSocket, you must override the notification functions for those network events of interest to your application. If you derive a class from class CSocket, it’s your choice whether to override the notification functions of interest. You can also use CSocket itself, in which case the notification functions default to doing nothing.

These functions are overridable callback functions. CAsyncSocket and CSocket convert messages to notifications, but you must implement how the notification functions respond if you wish to use them. The notification functions are called at the time your socket is notified of an event of interest, such as the presence of data to be read.

MFC calls the notification functions to let you customize your socket’s behavior at the time it is notified. For example, you might call Receive from your OnReceive notification function. That is, on being notified that there is data to read, you call Receive to read it. This approach isn’t necessary, but it is a valid scenario. As an alternative, you might use your notification function to track progress, print TRACE messages, and so on.

You can take advantage of these notifications by overriding the notification functions in a derived socket class and providing an implementation. For an example implementation, see the notification function overrides in the MFC Advanced Concepts samples CHATTER and CHATSRVR.

During an operation such as receiving or sending data, a CSocket object becomes synchronous. During the synchronous state, any notifications meant for other sockets are queued while the current socket waits for the notification it wants. (For example, during a Receive call, the socket wants a notification to read.) Once the socket completes its synchronous operation and becomes asynchronous again, other sockets can begin receiving the queued notifications.

Important In CSocket, the OnConnect notification function is never called. For connections, you simply call Connect, which will return when the connection is completed (either successfully or in error). How connection notifications are handled is an MFC implementation detail.

For details about each notification function see the function under class CAsyncSocket in the Class Library Reference. For source code and information about MFC samples, see MFC Samples.

What do you want to know more about?

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Deriving from Socket Classes

  • Windows Sockets: How Sockets with Archives Work

  • Windows Sockets: Blocking

  • Windows Sockets: Byte Ordering

  • Windows Sockets: Converting Strings


Windows Sockets: Blocking

Home | Overview | How Do I | Sample

This article and two companion articles explain several issues in Windows Sockets programming. This article covers blocking. The other issues are covered in the articles: Windows Sockets: Byte Ordering and Windows Sockets: Converting Strings.

If you use or derive from class CAsyncSocket, you will need to manage these issues yourself. If you use or derive from class CSocket, MFC manages them for you.

Blocking

A socket can be in “blocking mode” or “nonblocking mode.” The functions of sockets in blocking (or synchronous) mode do not return until they can complete their action. This is called blocking because the socket whose function was called can’t do anything — is blocked — until the call returns. A call to the Receive member function, for example, might take an arbitrarily long time to complete as it waits for the sending application to send (this is if you are using CSocket, or using CAsyncSocket with blocking). If a CAsyncSocket object is in nonblocking mode (operating asynchronously), the call returns immediately and the current error code, retrievable with the GetLastError member function, is WSAEWOULDBLOCK, indicating that the call would have blocked had it not returned immediately because of the mode. (CSocket never returns WSAEWOULDBLOCK. The class manages blocking for you.)

The behavior of sockets is different under Windows 95 and Windows NT than under Windows 3.1 (16 bit). Unlike Windows 3.1, both Windows 95 and Windows NT use preemptive multitasking and provide multithreading. Under these 32-bit operating systems, you can put your sockets in separate worker threads. A socket in a thread can block without interfering with other activities in your application and without spending compute time on the blocking. For information on multithreaded programming, see the article Multithreading.

Note In multithreaded applications, you can use the blocking nature of CSocket to simplify your program’s design without affecting the responsiveness of the user interface. By handling user interactions in the main thread and CSocket processing in alternate threads, you can separate these logical operations. In an application that is not multithreaded, these two activities must be combined and handled as a single thread, which usually means using CAsyncSocket so you can handle communications requests on demand, or overriding CSocket::OnMessagePending to handle user actions during lengthy synchronous activity.

The rest of this discussion is for programmers targeting Windows 3.1.

Normally, if you’re using CAsyncSocket, you should avoid using blocking operations and operate asynchronously instead. In asynchronous operations, from the point at which you receive a WSAEWOULDBLOCK error code after calling Receive, for example, you wait until your OnReceive member function is called to notify you that you can read again. Asynchronous calls are made by calling back your socket’s appropriate callback notification function, such as OnReceive.

Under Windows, blocking calls are considered bad practice. By default, CAsyncSocket supports asynchronous calls, and you must manage the blocking yourself using callback notifications. Class CSocket, on the other hand, is synchronous. It pumps Windows messages and manages blocking for you.

For more information about blocking, see the Windows Sockets specification. For more information about “On” functions, see the articles Windows Sockets: Socket Notifications and Windows Sockets: Deriving from Socket Classes.

What do you want to know more about?

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Using Sockets with Archives

  • Windows Sockets: Background

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets

See Also CAsyncSocket::OnSend


Windows Sockets: Byte Ordering

Home | Overview | How Do I | Sample

This article and two companion articles explain several issues in Windows Sockets programming. This article covers byte ordering. The other issues are covered in the articles: Windows Sockets: Blocking and Windows Sockets: Converting Strings.

If you use or derive from class CAsyncSocket, you will need to manage these issues yourself. If you use or derive from class CSocket, MFC manages them for you.

Byte Ordering

Different machine architectures sometimes store data using different byte orders. For example, Intel-based machines store data in the reverse order of Macintosh (Motorola) machines. Intel’s byte order, called “little-Endian,” is also the reverse of the network standard “big-Endian” order. The following table explains these terms.

Big- and Little-Endian Byte Ordering

Byte ordering | Meaning
Big-Endian | The most significant byte is on the left end of a word.
Little-Endian | The most significant byte is on the right end of a word.

Typically, you don’t have to worry about byte-order conversion for data that you send and receive over the network, but there are situations in which you must convert byte orders.

When You Must Convert Byte Orders

You need to convert byte orders in the following situations:

  • You’re passing information that needs to be interpreted by the network, as opposed to the data you’re sending to another machine. For example, you might pass ports and addresses, which the network must understand.

  • The server application with which you’re communicating is not an MFC application (and you don’t have source code for it). This calls for byte order conversions if the two machines don’t share the same byte ordering.

When You Don’t Have to Convert Byte Orders

You can avoid the work of converting byte orders in the following situations:

  • The machines on both ends can agree not to swap bytes, and both machines use the same byte order.

  • The server you’re communicating with is an MFC application.

  • You have source code for the server you’re communicating with, so you can tell explicitly whether you must convert byte orders or not.

  • You can port the server to MFC.

    This is fairly easy to do, and the result is usually smaller, faster code. For information, see the MFC Migration Kit, which is included with Visual C++.

Working with CAsyncSocket, you must manage any necessary byte-order conversions yourself. Windows Sockets standardizes the “big-Endian” byte-order model and provides functions to convert between this order and others. CArchive, however, which you use with CSocket, uses the opposite (“little-Endian”) order — but CArchive takes care of the details of byte-order conversions for you. By using this standard ordering in your applications, or using Windows Sockets byte-order conversion functions, you can make your code more portable.

The ideal case for using MFC sockets is when you’re writing both ends of the communication: using MFC at both ends. If you’re writing an application that will communicate with non-MFC applications, such as an FTP server, you’ll probably need to manage byte-swapping yourself before you pass data to the archive object, using the Windows Sockets conversion routines, ntohs, ntohl, htons, and htonl. An example of these functions used in communicating with a non-MFC application appears later in this article.

Note When the other end of the communication is not an MFC application, you also must avoid streaming C++ objects derived from CObject into your archive because the receiver will not be able to handle them. See the Caution in the article Windows Sockets: Using Sockets with Archives.

For more information about byte orders, see the Windows Sockets specification, available in the Win32 SDK.

A Byte-Order Conversion Example

The following example shows a serialization function for a CSocket object that uses an archive. It also illustrates using the byte-order conversion functions in the Windows Sockets API.

This example presents a scenario in which you are writing a client that communicates with a non-MFC server application for which you have no access to the source code. In this scenario, you must assume that the non-MFC server uses standard network byte order. In contrast, your MFC client application uses a CArchive object with a CSocket object, and CArchive uses “little-Endian” byte order, the opposite of the network standard.

Suppose the non-MFC server with which you plan to communicate has an established protocol for a message packet like the following:

struct Message
{
    long MagicNumber;
    unsigned short Command;
    short Param1;
    long Param2;
};

In MFC terms, this would be expressed as follows:

struct Message
{
    long m_lMagicNumber;
    short m_nCommand;
    short m_nParam1;
    long m_lParam2;

    void Serialize( CArchive& ar );
};

In C++, a struct is essentially the same thing as a class. The Message structure can have member functions, such as the Serialize member function declared above. The Serialize member function might look like this:

void Message::Serialize(CArchive& ar)
{
    if (ar.IsStoring())
    {
        ar << (DWORD)htonl(m_lMagicNumber);
        ar << (WORD)htons(m_nCommand);
        ar << (WORD)htons(m_nParam1);
        ar << (DWORD)htonl(m_lParam2);
    }
    else
    {
        WORD w;
        DWORD dw;
        ar >> dw;
        m_lMagicNumber = ntohl((long)dw);
        ar >> w ;
        m_nCommand = ntohs((short)w);
        ar >> w;
        m_nParam1 = ntohs((short)w);
        ar >> dw;
        m_lParam2 = ntohl((long)dw);
    }
}

This example calls for byte-order conversions of data because there is a clear mismatch between the byte ordering of the non-MFC server application on one end and the CArchive used in your MFC client application on the other end. The example illustrates several of the byte-order conversion functions that Windows Sockets supplies. The following table describes these functions.

Windows Sockets Byte-Order Conversion Functions

Function | Purpose
ntohs | Convert a 16-bit quantity from network byte order to host byte order (Big-Endian to Little-Endian).
ntohl | Convert a 32-bit quantity from network byte order to host byte order (Big-Endian to Little-Endian).
htons | Convert a 16-bit quantity from host byte order to network byte order (Little-Endian to Big-Endian).
htonl | Convert a 32-bit quantity from host byte order to network byte order (Little-Endian to Big-Endian).

Another point of this example is that when the socket application on the other end of the communication is a non-MFC application, you must avoid doing something like the following:

ar << pMsg;

where pMsg is a pointer to a C++ object derived from class CObject. This will send extra MFC information associated with objects and the server won’t understand it, as it would if it were an MFC application.

What do you want to know more about?

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Background

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets


Windows Sockets: Converting Strings

Home | Overview | How Do I | Sample

This article and two companion articles explain several issues in Windows Sockets programming. This article covers converting strings. The other issues are covered in the articles: Windows Sockets: Blocking and Windows Sockets: Byte Ordering.

If you use or derive from class CAsyncSocket, you will need to manage these issues yourself. If you use or derive from class CSocket, MFC manages them for you.

Converting Strings

If you communicate between applications that use strings stored in different wide-character formats, such as Unicode or multibyte character sets (MBCS), or between one of these and an application using ANSI character strings, you must manage the conversions yourself under CAsyncSocket. The CArchive object used with a CSocket object manages this conversion for you via the capabilities of class CString. For more information, see the Windows Sockets specification, located in the Win32 SDK.

What do you want to know more about?

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Using Sockets with Archives

  • Windows Sockets: Background

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets


Windows Sockets: Ports and Socket Addresses

Home | Overview | How Do I | Sample

This article explains the terms “port” and “address” as used with Windows Sockets.

Port

A port identifies a unique process for which a service can be provided. In the present context, a port is associated with an application that supports Windows Sockets. The idea is to identify each Windows Sockets application uniquely so you can have more than one Windows Sockets application running on a machine at the same time.

Certain ports are reserved for common services, such as FTP. You should avoid using those ports unless you are providing that kind of service. The Windows Sockets specification details these reserved ports. The file WINSOCK.H also lists them.

To let the Windows Sockets DLL select a usable port for you, pass 0 as the port value. MFC selects a port value greater than 1,024 decimal. You can retrieve the port value that MFC selected by calling the CAsyncSocket::GetSockName member function.

Socket Address

Each socket object is associated with an Internet Protocol (IP) address on the network. Typically, the address is a machine name, such as “ftp.microsoft.com”, or a dotted number, such as “128.56.22.8”.

When you seek to create a socket, you typically don’t need to specify your own address.

Important It’s possible that your machine has multiple network cards (or your application might someday run on such a machine), each representing a different network. If so, you might need to give an address to specify which network card the socket will use. This is certain to be an advanced usage and a possible portability issue.

What do you want to know more about?

  • Windows Sockets: Using Class CAsyncSocket

  • Windows Sockets: Using Sockets with Archives

  • Windows Sockets: How Sockets with Archives Work

  • Windows Sockets: Stream Sockets

  • Windows Sockets: Datagram Sockets


Win32 Topics

Home | Overview | How Do I

This family of articles covers several subjects not included in the Win32 SDK documentation or not covered there from the perspective of Visual C++.

For most Win32 programming topics, see the Win32 Programmer’s Reference and the Programmer’s Guide to Windows 95. For your convenience, a number of links to those topics are provided below.

The Samples node gives information about Win32 programming samples. These are distinct from the MFC programming samples under that same node.

You will find additional information in Windows 95 System Limitations.

What do you want to know more about?

The WINDOWS.H Include File and STRICT Type Checking

  • WINDOWS.H, the primary Windows header file

  • STRICT type checking

Other Topics from the Win32 Programmer’s Reference

  • Carets

  • Clipboard

  • Common Dialog Boxes

  • Cursors

  • Dialog Boxes

  • Graphics Device Interface (GDI)

  • Hooks

  • Icons

  • International Features

  • Keyboard Accelerators

  • Keyboard Input

  • Menus

  • Messages and Message Queues

  • Mouse Input

  • Multimedia Services see the Graphics and Multimedia Services node in the Platform SDK

  • Multiple Document Interface

  • Network Services

  • Painting and Drawing

  • Rectangles

  • Shell Features

  • System Services

  • Timers

  • Window Classes

  • Window Controls

  • Window Procedures

  • Window Properties

  • Windows

Other Topics from the Programmer’s Guide to Windows 95

  • Using the Win32 API

  • Pens

  • Dragging and Dropping

  • Windows Shell API

  • Installing Applications

  • Using Common Controls

  • Using the Registry

  • Version Differences

  • Windows 95 System Limitations

  • Windows 95 Architecture

  • Using Windows 95 Features:
    • Device I/O Control

    • Exclusive Volume Locking

    • FAT32 File System

    • Long Filenames

    • MS-DOS Extensions

    • Thunk Compiler

    • Tool Help Library

    • Virtual Machine Services

    • Windows 95 Service Control Manager


WINDOWS.H and STRICT Type Checking

Home | Overview | How Do I

The WINDOWS.H file contains definitions, macros, and structures to help you write source code that is portable between versions of Microsoft Windows. Some of the WINDOWS.H features are enabled when you define the STRICT symbol in the Project Settings dialog box, on the command line, or in a makefile. This article family explains the advantages of STRICT features and how using them affects the writing of code.

For more information about STRICT, see Using STRICT to Improve Type Checking.


New Types and Macros

Home | Overview | How Do I

Porting 16-Bit Code to 32-Bit Windows introduced some new standard types for programming in Windows. The old types, such as FAR PASCAL for declaring window procedures, may work in existing code but are not guaranteed to work in all future versions of Windows. Therefore, you should convert your code to use the new standards wherever appropriate.

What do you want to know more about?

  • General data types

  • Utility macros

  • New handle types


General Data Types

Home | Overview | How Do I

The following table summarizes the new standard types defined in WINDOWS.H. These types are polymorphic (they can contain different kinds of data) and are generally useful throughout applications. Other new types, handles, and function pointers also are introduced in other topics (listed in New Types and Macros). Also see Simple Types in the Win32 documentation.

Typedef | Description
WINAPI | Use in place of FAR PASCAL in API declarations. If you are writing a DLL with exported API entry points, you can use this for your own APIs.
CALLBACK | Use in place of FAR PASCAL in application callback routines such as window procedures and dialog procedures.
LPCSTR | Same as LPSTR, except used for read-only string pointers. Defined as (const char FAR*).
UINT | Portable unsigned integer type whose size is determined by host environment (32 bits for Windows NT and Windows 95). Synonym for unsigned int. Used in place of WORD except in the rare cases where a 16-bit unsigned quantity is desired even on 32-bit platforms.
LRESULT | Type used for return value of window procedures.
LPARAM | Type used for declaration of lParam, the fourth parameter of a windows procedure.
WPARAM | Type used for declaration of wParam, the third parameter of a windows procedure (a polymorphic data type).
LPVOID | Generic pointer type, equivalent to (void *). Should be used instead of LPSTR.


Utility Macros

Home | Overview | How Do I

WINDOWS.H provides a series of utility macros that are useful for working with the types listed in General Data Types. The utility macros listed in the following table help create and extract data from these types. The FIELDOFFSET macro is particularly useful when you need to give the numeric offset of a structure member as an argument.

Utility | Description
MAKELPARAM(low, high) | Combines two 16-bit quantities into an LPARAM.
MAKELRESULT(low, high) | Combines two 16-bit quantities into an LRESULT.
MAKELP(sel, off) | Combines a selector and an offset into a FAR VOID* pointer. Useful only for Windows 3.x.
SELECTOROF(lp) | Extracts the selector part of a far pointer. Returns a UINT. Useful only for Windows 3.x.
OFFSETOF(lp) | Extracts the offset part of a far pointer. Returns a UINT. Useful only for Windows 3.x.
FIELDOFFSET(type, field) | Calculates the offset of a member of a data structure. The type is the type of structure, and field is the name of the structure member or field.


New Handle Types

Home | Overview | How Do I

In addition to the existing Windows handle types such as HWND, HDC, HBRUSH, and so on, WINDOWS.H defines the following new handle types. They are particularly important if STRICT type checking is enabled, but you can use them even if you do not define STRICT.

Handle | Description
HINSTANCE | Instance handle type
HMODULE | Module handle type
HBITMAP | Bitmap handle type
HLOCAL | Local handle type
HGLOBAL | Global handle type
HTASK | Task handle type
HFILE | File handle type
HRSRC | Resource handle type
HGDIOBJ | Generic GDI object handle type (except HMETAFILE)
HMETAFILE | Metafile handle type
HDWP | DeferWindowPos( ) handle
HACCEL | Accelerator table handle
HDRVR | Driver handle


Using STRICT to Improve Type Checking

Home | Overview | How Do I

When you define the STRICT symbol, you enable features that require more care in declaring and using types. This helps you write more portable code. This extra care will also reduce your debugging time. Enabling STRICT redefines certain data types so that the compiler won’t permit assignment from one type to another without an explicit cast. This is especially helpful with Windows code. Errors in passing data types are reported at compile time instead of causing fatal errors at run time.

When STRICT is defined, WINDOWS.H type definitions change as follows:

  • Specific handle types are defined to be mutually exclusive; for example, you won’t be able to pass an HWND where an HDC type argument is required. Without STRICT, all handles are defined as integers, so the compiler doesn’t prevent you from using one type of handle where another type is expected.

  • All callback function types (dialog procedures, window procedures, and hook procedures) are defined with full prototypes. This prevents you from declaring callback functions with incorrect parameter lists.

  • Parameter and return value types that should use a generic pointer are declared correctly as LPVOID instead of as LPSTR or another pointer type.

  • The COMSTAT structure is declared according to the ANSI standard.

What do you want to know more about?

  • Enabling STRICT type checking

  • Making your application STRICT compliant

  • Using STRICT type checking

  • Accessing the COMSTAT structure

  • Interpreting error messages affected by STRICT


Enabling STRICT Type Checking

Home | Overview | How Do I

To enable STRICT type checking, define the symbol name "STRICT." Open the Project Settings dialog box, select the C/C++ tab, select General in the Categories box, and type STRICT in the Preprocessor Definitions box. You can also specify this definition on the command line or in a makefile by giving /DSTRICT as a compiler option.

To define STRICT on a file-by-file basis (supported by C but not C++, as explained in the note that follows), insert a #define statement before including WINDOWS.H in files where you want to enable STRICT:

#define STRICT
#include WINDOWS.H

For best results, you should also set the warning level for error messages to at least /W3. This is always advisable with applications for Windows, because a coding practice that causes a warning (for example, passing the wrong number of parameters) usually causes a fatal error at run time if it is not corrected.

Note If you are writing a C++ application, you don’t have the option of applying STRICT to only some of your source files. Because of the way C++ “type safe linking” works, mixing STRICT and non-STRICT source files in your application can cause linking errors.


Making Your Application STRICT Compliant

Home | Overview | How Do I

Some source code that in the past compiled successfully might produce error messages when you enable STRICT type checking. The following sections describe the minimal requirements for making your code compile when STRICT is enabled. Additional steps are recommended, especially if you want to produce portable code. These are covered in Using STRICT Type Checking.

General Requirements

The principal requirement is that you must declare correct handle types and function pointers instead of relying on more general types such as unsigned int and FARPROC. You cannot use one handle type where another is expected. This also means that you may have to change function declarations and use more type casts.

For best results, the generic HANDLE type should be used only when necessary. Consult New Types and Macros for a list of new specific handle types.

Using Function Pointers

Always declare function pointers with the proper function type (such as DLGPROC or WNDPROC) rather than FARPROC. You’ll need to cast function pointers to and from the proper function type when using MakeProcInstance, FreeProcInstance, and other functions that take or return a FARPROC, as shown in the following code:

BOOL CALLBACK DlgProc(HWND hwnd, UINT msg, WPARAM wParam,
                       LPARAM lParam);
DLGPROC lpfnDlg;

lpfnDlg = (DLGPROC)MakeProcInstance((FARPROC)DlgProc, hinst);
...
FreeProcInstance((FARPROC)lpfnDlg);

Declaring Functions Within Your Application

Make sure all application functions are declared. Placing all function declarations in an include file is recommended because you can easily scan your declarations and look for parameter and return types that should be changed.

If you use the /Zg compiler option to create header files for your functions, remember that you’ll get different results depending on whether you have enabled STRICT type checking. With STRICT disabled, all handle types generate the same base type (unsigned short in Windows 3.x). With STRICT enabled, they generate base types such as HWND __near * or HDC __near *. To avoid conflict, you need to re-create the header file each time you enable or disable STRICT, or edit the header file to use the types HWND, HDC, HANDLE, and so on, instead of the base types.

Any API function declarations that you copied from WINDOWS.H into your source code may have changed, and your local declaration may be out of date. Remove your local declaration.

Functions That Require Casts

Some API functions have generic return types or parameters. For example, a function like SendMessage returns data that may be any number of types, depending on the context. When you see any of these functions in your source code, make sure that you use the correct type cast and that it is as specific as possible.

The following table summarizes these functions.

API function | Comment
LocalLock | Cast result to the proper kind of data pointer.
GlobalLock | Cast result to the proper kind of data pointer.
GetWindowWord | Cast result to appropriate data type.
GetWindowLong | Cast result to appropriate data type.
SetWindowWord | Cast argument as it is passed to function.
SetWindowLong | Cast argument as it is passed to function.
SendMessage | Cast result to appropriate data type; cast to UINT before casting to a handle type.
DefWindowProc | See comment for SendMessage.
SendDlgItemMessage | See comment for SendMessage.

When you call SendMessage, DefWindowProc, or SendDlgItemMessage, you should first cast the result to type UINT. You need to take similar steps for any API function that returns LRESULT or LONG, where the result contains a handle. This is necessary for writing portable code because the size of a handle is either 16 bits or 32 bits, depending on the version of Windows. The (UINT) cast ensures proper conversion. The following code shows an example in which SendMessage returns a handle to a brush:

HBRUSH hbr;

hbr = (HBRUSH)(UINT)SendMessage(hwnd, WM_CTLCOLOR, ..., ...);

The CreateWindow Function

The CreateWindow and CreateWindowEx hmenu parameter is sometimes used to pass an integer control ID. In this case, you must cast the ID to an HMENU type:

HWND hwnd;
int id;

hwnd = CreateWindow("Button", "Ok", BS_PUSHBUTTON,
        x, y, cx, cy, hwndParent,
        (HMENU)id,      // Cast required here
        hinst,
        NULL);


Using STRICT Type Checking

Home | Overview | How Do I

To get the most benefit from STRICT type checking, there are additional guidelines you should follow. Your code will be more portable in future versions of Windows if you make the following changes:

Change | To
HANDLE | A specific handle such as HINSTANCE, HMODULE, HGLOBAL, HLOCAL, and so on
WORD | UINT, except where you want a 16-bit value even when the platform is 32 bits
WORD | WPARAM, where wParam is declared
LONG | LPARAM or LRESULT as appropriate

Whenever you need an integer data type, you should declare it as UINT except where a 16-bit value is specifically required (as in a structure or parameter). Even if a variable never exceeds the range of a 16-bit integer, it can be handled by the processor more efficiently if it is 32 bits.

The types WPARAM, LPARAM, LRESULT, and void * are “polymorphic data types.” They hold different kinds of data at different times, even when STRICT type checking is enabled. To get the benefit of type checking, you should cast values of these types as soon as possible. Note that message crackers (as well as the Microsoft Foundation classes) automatically recast wParam and lParam for you in a portable way.

Take special care to distinguish HMODULE and HINSTANCE types. Even with STRICT enabled, they are defined as the same base type. Most kernel module management functions use HINSTANCE types, but there are a few API functions that return or accept only HMODULE types.


Accessing the COMSTAT Structure

Home | Overview | How Do I

The Windows 3.x declaration of the COMSTAT structure is incompatible with ANSI standards. WINDOWS.H now defines the COMSTAT structure, for compatibility with ANSI compilers, so that the /W4 option does not issue warnings.

To support backward compatibility of source code, WINDOWS.H does not use the new structure definition unless the version of Windows (as indicated by WINVER) is 3.x or later, or if STRICT is defined. When you enable STRICT, the presumption is that you are trying to write portable code. Therefore, WINDOWS.H uses the new COMSTAT structure for all versions of Windows if STRICT is enabled.

The new structure definition replaces the bit fields with flags that access bits in a single field, named status, as shown in the following table. Each flag turns on a different bit.

Windows 3.x field name | Flag accessing the status field
fCtsHold | CSTF_CTSHOLD
fDsrHold | CSTF_DSRHOLD
fEof | CSTF_EOF
fRlsdHold | CSTF_RLSDHOLD
fTxim | CSTF_TXIM
fXoffHold | CSTF_XOFFHOLD
fXoffSent | CSTF_XOFFSENT

If your code accesses any of these status fields, you need to change your code as appropriate. For example, suppose you have the following code written for Windows 3.x:

if (comstat.fEof || fCondition)
    comstat.fCtsHold = TRUE;
    comstat.fTxim = FALSE;

This code should be replaced by code that accesses individual bits of the status field by using flags. Note the use of bitwise operators:

if ((comstat.status & CSTF_EOF) || fCondition)
    comstat.status |= CSTF_CTSHOLD;
    comstat.status &= ~CSTF_TXIM;


Interpreting Error Messages Affected by STRICT

Home | Overview | How Do I

Enabling STRICT type checking may affect the kind of error messages you receive. With STRICT enabled, all handle types are defined as pointer types. When you incorrectly use these types (for example, passing an int where an HDC is expected), you will get warning messages referring to errors in pointer indirection.

STRICT also requires that FARPROC function pointers be recast as more specific function pointer types such as DLGPROC. However, MakeProcInstance and FreeProcInstance still work with the FARPROC type. If you do not cast between FARPROC and the appropriate function pointer type, the compiler will warn you about an error in function parameter lists.

Note that using MakeProcInstance is useful for portability, if you want to use the same source to compile for Windows 3.x. Under Win32, however, MakeProcInstance performs no operation, but returns the function name.


Windows 95 Functionality

Home | Overview | How Do I

Microsoft Visual C++ and the Microsoft Foundation Class Library are designed to help you write applications for Windows 95. Several of the requirements for the Windows 95 logo are satisfied automatically by any MFC application built using Visual C++. Fulfilling the remaining requirements, such as OLE support, requires knowledge of the specific nature of your application, making it impossible for MFC to generate a completely Windows 95-logo–compliant application automatically. However, MFC provides classes containing all the generic code needed, so that all you have to do is add the code specific to your application. This article describes the process of meeting the logo requirements for a sample MFC application.

Note This information is not a substitute for the Windows 95 Logo Criteria document. To get a copy of the Logo Criteria document and related documents, see the section For More Information on the Windows 95 Logo.

See Also Summary of the Logo Requirements


Summary of the Logo Requirements

Home | Overview | How Do I

There are five basic requirements your application must meet to qualify for the Windows 95 logo, no matter what type of application it is:

  • Win32 executable

    Your application must be a Win32 executable file using the PE (Portable Executable) format. This requirement is satisfied automatically, because Visual C++ for the Intel platform always produces executable files in the PE format.

    If you have a 16-bit application that you need to port, see Porting 16-Bit Code to 32-Bit Windows.

  • UPI and Shell support

    Your application must follow the Windows 95 application setup guidelines, register large and small icons, and use system color and metrics. It’s also recommended that your application provide context menus through the right mouse button, use the common dialogs and controls, and follow the user interface guidelines set forth in the Windows Interface Guidelines for Software Design on the MSDN Library CD.

    The section Following UPI Recommendations below discusses how to add this support using MFC.

  • Windows NT compatibility

    Your application must run successfully on both Windows 95 and Windows NT 3.5 (or greater). If your application uses functionality specific to either operating system, its behavior must degrade gracefully when run on the other operating system (that is, an execution error should not result).

    Meeting this requirement depends on your use of API functions specific to Windows 95 or Windows NT. For a list of these APIs, see the paper "Diving into the Requirements for the Windows 95 Logo" on the MSDN Library CD.

  • Long file name support

    Your application must be able to accept and store long file names and display them in its title bar, in dialogs and controls, and so on.

    The MFC library supports the use of long file names, so you can pass a long file name to any MFC function taking a file name as a parameter. You should also use the MFC common dialog class CFileDialog when requesting a file name from the user. Make sure that any file name-handling code of your own can handle file names longer than eight characters and file names containing spaces or other special characters. For more information on long file names, see Supporting Long File names on the MSDN Library CD.

  • Plug and Play support

    This is recommended but not required. Your application should respond appropriately to the WM_DEVICECHANGE, WM_DISPLAYCHANGE, and WM_POWERBROADCAST messages, which signal changes in peripheral devices, the display resolution, or the system power status, respectively.

    The MFC library responds to the WM_DISPLAYCHANGE message and resizes windows and toolbars according to the new system metrics. How an application should respond to the WM_DEVICECHANGE and WM_POWERBROADCAST messages depends on the specific application; for an example of the most common response to these messages, see the Plug-and-Play awareness component in the Gallery.

There are also three other requirements your application must meet if it is file-based (that is, if your application’s primary purpose is to create, edit, and save files):

  • UNC path support

    Your application must support Universal Naming Convention (UNC) paths. That means your application must be able to accept and store paths of the form “\\server\share\directory” directly, without requiring the user to assign a drive letter to the server beforehand.

    The MFC library supports the use of UNC paths, so you can pass a UNC path to any MFC function taking a path as a parameter. You should also use the MFC common dialog class CFileDialog when requesting a file name from the user. Make sure that any pathname-handling code that you write can handle double backslashes instead of a drive letter at the beginning of a path.

  • OLE support

    Your application must either be an OLE container or an OLE server, or both. In addition, if it’s an OLE container, it must act as a target for drag-and-drop operations, and if it’s an OLE server, it must act as a source for drag-and-drop operations. It’s also recommended (thought not required) that you support Automation and provide summary information with your documents.

    The section Adding OLE Support discusses how to add this functionality, using MFC.

  • MAPI support

    Your application must include a Send Mail command on the File menu to enable the user to send the current document as a piece of mail, using MAPI or the Common Messaging Call (CMC) API.

    The section Adding MAPI Support discusses how to add this functionality, using MFC.

There are certain additions and exceptions to the previous requirements, depending on the type of application you’re developing; these additions and exceptions are described in the "Logo Criteria" document.

The remainder of this section on Windows 95 logo compliance describes the changes made to the DRAWCLI sample application to make it meet the Windows 95 logo requirements, as well as certain user-interface recommendations; you can use this discussion as a guide for modifying your own MFC application.


Following UPI Recommendations

Home | Overview | How Do I

Your Windows 95 application must define both large and small icons. AppWizard automatically defines default 32x32 and 16x16 icons for both the application and the document type when generating MFC applications. If you replace the default icons with your own, remember to replace both the large and small versions. In addition, you have to register the icon for your document type with the system registry under the DefaultIcon key. MFC does this with the CWinApp::RegisterShellFileTypes function; AppWizard inserts a call to this function automatically if you specify a three-letter filetype extension for your application’s document. You can also register the icon in your setup application; see Creating a Setup and an Uninstall Program below for more information.

Your Windows 95 application must use the system colors and metrics for its dialogs to be consistent with the user’s settings. The MFC library calls the GetSysColor and GetSystemMetrics API functions to determine how dialogs and controls should be displayed. As a result, your MFC application’s appearance will automatically reflect the system colors and metrics, even if the user changes some attribute while the application is running.

It’s also recommended, though not required, that your Windows 95 application use the Windows common dialogs where applicable. The common dialogs provide a great deal of functionality in their support of long file names and UNC paths, as mentioned above. An application that uses the MFC framework automatically uses the common file and print dialogs, and if you want to use any of the other common dialogs, you can use the MFC library’s wrappers. See Technical Note 60 and the descriptions of CFileDialog, CPrintDialog, CFindReplaceDialog, CColorDialog, and CFontDialog in the Class Library Reference.


Using Tabbed Property Pages

Home | Overview | How Do I

It’s recommended that your Windows 95 application use tabbed property pages where applicable. Tabbed property pages are useful for dialogs whose purpose is to let the user modify the attributes of some object on the screen. MFC provides support for property pages through the classes CPropertySheet and CPropertyPage.

The DRAWCLI sample previously used a dialog box to allow the user to set the fill mode and the pen size. For consistency with the Windows 95 user-interface guidelines, DRAWCLI now uses a property page to do so.

You can use the Gallery to add a property sheet to your application. However, for DRAWCLI, the task is not adding a property sheet, but converting an existing dialog into a property sheet. Depending on your application’s needs, you can use the Gallery to add property sheets and modify them as needed, or you can add them manually.

If you’re converting an existing dialog box to a property page, use the following procedure:

  • From within Visual C++’s dialog editor, do the following:
    • Check the Disabled and Titlebar properties for the dialog.

    • Choose the Child style and Thin borders.

    • Optional: Modify the caption for the dialog. This caption will now appear on the tab for the property page instead of in the dialog’s title bar.
  • Change the base class of your dialog class from CDialog to CPropertyPage and modify the constructor for your dialog class to call CPropertyPage’s constructor in its base-initializer list.

To display the property page, attach it to a CPropertySheet object and call DoModal on the CPropertySheet object. Here’s how DRAWCLI does it, in its implementation of CDrawObj::OnOpen:

CPropertySheet sheet( "Shape Properties" );
CRectDlg dlg; // derived from CPropertyPage

dlg.m_bNoFill = !m_bBrush;
dlg.m_penSize = m_bPen ? m_logpen.lopnWidth.x : 0;
sheet.AddPage( &dlg );

if (sheet.DoModal() != IDOK)
   return;

m_bBrush = !dlg.m_bNoFill;
m_bPen = dlg.m_penSize > 0;
if (m_bPen)
{
   m_logpen.lopnWidth.x = dlg.m_penSize;
   m_logpen.lopnWidth.y = dlg.m_penSize;
}

The string passed to the constructor for CPropertySheet is used as the title in the dialog’s title bar. Before calling DoModal, the current values are copied into the property sheet. After DoModal returns, the new values are copied back.

The following figure shows what DRAWCLI’s property page looks like. For more information on implementing property pages with MFC, see Property Sheets and Property Pages and the descriptions of CPropertyPage and CPropertySheet in the Class Library Reference. For a demonstration of different types of property sheets, see the PROPDLG sample application in the MFC samples.

DRAWCLI’s New Property Sheet


Using Common Controls

Home | Overview | How Do I

It’s recommended that your Windows 95 application use the common controls where applicable. Visual C++’s dialog editor offers the common controls on its control palette, and MFC provides classes for all the Windows common controls.

One place in the DRAWCLI sample where a common control can be used is in the dialog box for specifying the thickness of the drawing pen. DRAWCLI formerly used a simple edit control in which the user typed the pen thickness; now DRAWCLI adds a spin control, allowing the user to use the mouse or the arrow keys to increment or decrement the pen thickness.

You can add a spin control to your application by using the Visual C++ dialog editor; associate the spin control with an edit control by checking the Auto Buddy and Set Buddy Integer properties on the control’s property page. Next, use the Member Variables tab of the ClassWizard dialog to add a member variable for the spin control. This causes ClassWizard to do two things:

  • Declare a member of type CSpinButtonCtrl in the dialog class.

  • Add a call to DDX_Control in the dialog’s DoDataExchange member function, associating the spin control with the member variable.

You must manually add the statement #include <afxcmn.h> to your STDAFX.H file to include MFC’s common control support in an existing application. If you generate a new application with AppWizard, AppWizard now inserts this statement into STDAFX.H automatically.

Finally, override the OnInitDialog member function of the dialog class to initialize the spin control. Here’s what the function looks like in DRAWCLI:

BOOL CRectDlg::OnInitDialog()
{
   CDialog::OnInitDialog();

   m_SpinCtrl.SetRange(0, 100);
   m_SpinCtrl.SetBase(10);
   m_SpinCtrl.SetPos(1);
   return TRUE;
}

This function sets the initial, minimum, and maximum values for the spin control. It also sets the spin control to use decimal notation.

For more information on using MFC’s common control classes, see MFC: Windows 95 Support in Visual C++ Programmer’s Guide and the descriptions of CAnimateCtrl, CHeaderCtrl, CHotKeyCtrl, CListCtrl, CProgressCtrl, CSliderCtrl, CSpinButtonCtrl, CStatusBarCtrl, CTabCtrl, CToolBarCtrl, CToolTipCtrl, and CTreeCtrl in the Class Library Reference. For a demonstration of various common controls, see the CMNCTRL1, CMNCTRL2, and FIRE sample applications in the MFC samples.


Displaying a Shortcut Menu

Home | Overview | How Do I

It’s recommended that your Windows 95 application use the right mouse button for displaying a shortcut menu, providing easy access to the most commonly used commands. What commands you offer on your shortcut menu will depend on whether the menu is invoked for a particular window, a particular object, and so on. See Windows Interface Guidelines for Software Design on the MSDN Library CD for guidelines on what kind of commands you should offer.

You can use the Gallery to add a shortcut menu that applies to a given view class in your application. However, DRAWCLI displays the shortcut menu only when the right button is clicked over a selected object. Depending on your own application’s needs, you can use the shortcut menu offered by the Gallery as is, you can make modifications as required, or you can add one manually.

The DRAWCLI sample provides a shortcut menu containing several commands from the Edit menu.

To add a shortcut menu to your application, first use the Visual C++ menu editor to create a menu bar without a title, and then define the shortcut menu as the first menu.

To display the shortcut menu, your application needs a handler for the WM_CONTEXTMENU message. You can use ClassWizard to make the following changes to your source files:

  • Add a declaration for an OnContextMenu member function in the declaration of your view class.

  • Add an ON_WM_CONTEXTMENU macro in the message map for your view class.

  • Add a skeletal definition for the OnContextMenu member function.

You then fill in the definition of OnContextMenu. Here’s DRAWCLI’s implementation of CDrawView::OnContextMenu:

void CDrawView::OnContextMenu(CWnd* /*pWnd*/, CPoint point)
{
   // make sure window is active
   GetParentFrame()->ActivateFrame();

   CPoint local = point;
   ScreenToClient(&local);
   ClientToDoc(local);

   CDrawObj* pObj;
   pObj = GetDocument()->ObjectAt(local);
   if (pObj != NULL)
   {
      if (!IsSelected(pObj))
         Select(pObj, FALSE);
      UpdateWindow();

      CMenu menu;
      if (menu.LoadMenu(ID_POPUP_MENU))
      {
         CMenu* pPopup = menu.GetSubMenu(0);
         ASSERT(pPopup != NULL);

         pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON,
            point.x, point.y,
            AfxGetMainWnd()); // use main window for cmds
      }
   }
}

DRAWCLI displays a pop-up menu only when the right mouse button is clicked over an object, so this function first checks whether an object lies where the mouse event occurred, and if so, the function selects it. (OnContextMenu receives the location of the mouse event in screen coordinates, not in client coordinates like handlers such as OnLButtonDown. Accordingly, the function converts the coordinates using CWnd::ScreenToClient before doing hit-testing.) The function then loads the ID_POPUP_MENU menu and calls CMenu::GetSubMenu to get its first sub-menu. Finally, the function calls CMenu::TrackPopupMenu on the submenu to display it as a pop-up.

Note that, as long as the pop-up menu commands are duplicates of commands you’ve defined elsewhere, there’s no need to define any new ON_COMMAND or ON_UPDATE_COMMAND_UI macros.

You can also support shortcut menus in the Windows 95 shell. A shortcut menu that offers basic commands such as Delete and Rename is available for all files in the shell. Some commands, such as Open or Print, are enabled only if there is an application associated with the file’s extension. You can enable these commands for files created by your MFC application by calling CWinApp::RegisterShellFileTypes, passing TRUE as a parameter; the parameter is needed for shell registration to work properly under Windows 95. (AppWizard inserts a call to this automatically if you specify a file name extension for your files.) This function adds entries to the system registry that let the shell invoke your application to open or print a file. You can also write a shell-extension DLL that customizes the shortcut menu for your application’s files; for more information, see Context Menu Handlers on the MSDN Library CD.


Using the System Registry

Home | Overview | How Do I

Your Windows 95 application must not store any information in the WIN.INI and SYSTEM.INI files; instead, use the system registry to store any initialization information. MFC applications never store information in WIN.INI or SYSTEM.INI. Instead, they normally use a private .INI file to store information such as the MRU (most recently used) file list, the position of dockable toolbars, etc. Private .INI files are permissible for Windows 95 applications (though they are not recommended), as long as they are stored in the application directory and are deleted when the application is uninstalled.

You can make your MFC application compliant by using the CWinApp::SetRegistryKey function; this function makes your application use the registry instead of a private .INI file. Call this function from the InitInstance member function of your CWinApp-derived class, specifying the name of your software company (in string form) as the parameter; this creates a subkey in the registry (under HKEY_CURRENT_USER) with your software company’s name. After this function is called, all the information that your application would normally write to its .INI file is instead stored in the registry under that key.


Creating a Setup and an Uninstall Program

Home | Overview | How Do I

Your Windows 95 application must be accompanied by a setup program having a graphical user interface. This program must be named SETUP.EXE so it can be identified by the Add/Remove Programs applet in the Control Panel. Your application must also add entries to the system registry specifying the command needed to uninstall your application. Again, this allows your uninstall program to be identified by the Add/Remove Programs applet.

A complete discussion of what’s involved in writing your own setup and uninstall programs is beyond the scope of this article. For information on the requirements for setup and uninstall programs, see the article "Windows 95 Application Setup Guidelines for ISVs" on the MSDN Library CD.

However, as a shortcut for developing setup and uninstall programs, Visual C++ includes the SDK Edition of Stirling Software’s InstallSHIELD. Using this toolkit, you can write a script that specifies the steps you want performed during installation; the InstallSHIELD SETUP application uses this script to install your product. The DRAWCLI sample includes a setup script for use with InstallSHIELD.

The script for DRAWCLI’s setup program installs the executable file for DRAWCLI, the DLLs needed by DRAWCLI, a help file, and some sample files. You can use the script as a basis for creating your own setup program using InstallSHIELD.

At a minimum, the changes you need to make to the script are as follows:

  • Change the size requirements to reflect the sizes of your program files, help files, and sample files.

  • Change the application name.

  • Change the version number.

  • Change the company name. (This must be consistent with the one you specify in your call to CWinApp::SetRegistryKey).

  • Change the command lines for the program group items.

  • Change the filetype extension. (This must be consistent with the extension you specified in AppWizard; this is used by CWinApp::RegisterShellFileTypes).

  • Change the filetype name. (This must be consistent with the one generated by AppWizard for CDocTemplate::regFileTypeId; this is used by CWinApp::RegisterShellFileTypes).

Other changes may be necessary, depending on the details of the installation process for your application.

With InstallSHIELD, you don’t have to write a separate script for uninstallation. InstallSHIELD’s uninstall program, UNINST, uses a log file that is created automatically during the setup process. This log file enables UNINST to reverse the steps performed during setup.

For more information on using InstallSHIELD, see the InstallSHIELD User’s Guide. For more information on using the system registry, see "Integrating with the System" on the MSDN Library CD.

For a list of the files that you can redistribute with your application, see Redistributable Files in DLL Topics or the file Redistrb.wri in the \OS\System directory on the Visual C++ CD-ROM.


Adding OLE Support

Home | Overview | How Do I

The MFC library defines numerous classes for supporting OLE functionality, including classes that implement the standard OLE dialog boxes. AppWizard also provides support for the automated creation of OLE container and OLE server applications. See the OLE tutorials in Tutorials for information on using MFC and AppWizard to write OLE applications; the section Creating an OLE Server describes how to make the SCRIBBLE sample an OLE server. The section Creating an OLE Container describes how to write an OLE container, using the CONTAINER sample as an example.

The previous version of the DRAWCLI sample already had OLE container functionality implemented, so it was not necessary to add this feature to meet Windows 95 logo requirements. However, DRAWCLI previously did not have drag-and-drop support; the following section describes the addition of that functionality.

For other examples of OLE containers, see the CONTAINER and OCLIENT sample applications in the MFC samples. For examples of OLE servers, see the HIERSVR sample application and Step 7 of the SCRIBBLE tutorial sample in the MFC samples. MFC samples are found in Samples.


Being a Drop Target

Home | Overview | How Do I

Because DRAWCLI is an OLE container, it needs drop target functionality to meet the Windows 95 requirements. (Conversely, an OLE server needs drop source functionality.)

MFC provides support for drop-target functionality through the COleDropTarget class and certain member functions in the CView class. Being a drop target involves the following tasks:

  • Registering your window as a drop target.

  • Checking a COleDataObject object to see if you can accept a drop operation from it.

  • Providing target feedback for the user.

  • Scrolling the document when the mouse cursor moves near the border of the document window.

  • Performing a paste operation from a COleDataObject object.

Most of these tasks are application-specific, so MFC can’t complete them for you. However, MFC does provide support for scrolling a document during a drag-and-drop operation, which is traditionally one of the more difficult tasks involved in being a drop target. The following sections describe how the other tasks are completed by the DRAWCLI sample.

One requirement for being a drop target was already satisfied by the previous version of DRAWCLI: the ability to perform a paste operation from a COleDataObject object. The previous version of DRAWCLI allowed OLE embedded objects to be inserted with the Paste command; the new version of DRAWCLI takes advantage of this fact by reusing the existing CDrawView::PastEmbedded function. If your container application doesn’t support this use of the Paste command, you should add that before implementing drop-target functionality. For information on creating embedded objects with the Paste command, see Data Objects and Data Sources (OLE) and Clipboard: Copying and Pasting Data.


Registration

Home | Overview | How Do I

In order for DRAWCLI to be informed of drag-and-drop operations, it must register its windows as drop targets. This requires adding a member variable to CDrawView:

COleDropTarget m_dropTarget;

The COleDropTarget member is used to register the view as a drop target.

A DRAWCLI window should be registered as a drop target as soon as it’s created. Consequently, DRAWCLI needs a handler for the WM_CREATE message, which requires three modifications to the source files:

  • Adding a declaration for an OnCreate member function in the declaration of CDrawView.

  • Adding an ON_WM_CREATE macro in the message map for CDrawView.

  • Adding a definition for CDrawView::OnCreate.

You can use ClassWizard to provide the necessary declarations and provide a skeletal function definition.

Here’s what the implementation of CDrawView::OnCreate looks like:

int CDrawView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   if (CScrollView::OnCreate(lpCreateStruct) == -1)
      return -1;

   // register drop target
   if( m_dropTarget.Register( this ) )
      return 0;
   else
      return -1;
}

This function calls COleDropTarget::Register on the m_dropTarget member variable. This informs the OLE system DLLs that DRAWCLI windows are willing to accept dragged objects.

The function COleDropTarget::Revoke is called automatically when the destructor is called.


Providing Target Feedback

Home | Overview | How Do I

A drop target must provide user feedback, that is, the visual indication to the user of how the window would respond to a drag-and-drop operation. For an application such as a word processor, this might consist of a shaded caret indicating where the dropped object would be inserted. For DRAWCLI, user feedback consists of a focus rectangle indicating the size and position of the object if it were to be dropped.

DRAWCLI declares some new member variables to manage this user feedback. The relevant declarations in CDrawView are as follows:

CPoint m_dragPoint;         // current position
CSize m_dragSize;         // size of dragged object
CSize m_dragOffset;         // offset of focus rect
DROPEFFECT m_prevDropEffect;
static CLIPFORMAT m_cfObjectDescriptor;
BOOL m_bDragDataAcceptable;

BOOL GetObjectInfo(COleDataObject* pDataObject,
            CSize* pSize, CSize* pOffset);

Some of the member variables store the size and position of the focus rectangle. The m_bDragDataAcceptable is a flag indicating whether usable data is available from the drag-and-drop operation. The GetObjectInfo function is a helper function described below.

Two of the member variables must be initialized. One of them is m_prevDropEffect, which gets initialized in the CDrawView constructor:

m_prevDropEffect = DROPEFFECT_NONE;

The other one is m_cfObjectDescriptor; this was declared as a static member, which means that it must be initialized at file scope, outside of the CDrawView constructor:

CLIPFORMAT CDrawView::m_cfObjectDescriptor =
    (CLIPFORMAT)::RegisterClipboardFormat(_T("Object Descriptor"));

DRAWCLI registers the string “Object Descriptor” so it can get the handle for the CF_OBJECTDESCRIPTOR Clipboard format defined by OLE. This handle is used below in the CDrawView::GetObjectInfo helper function.

Before DRAWCLI can draw this focus rectangle, it needs to know the size of the object. This is the purpose of the GetObjectInfo helper function; this function queries a data object for the CF_OBJECTDESCRIPTOR clipboard format:

BOOL CDrawView::GetObjectInfo(COleDataObject* pDataObject,
   CSize* pSize, CSize* pOffset)
{
   ASSERT(pSize != NULL);

   // get object descriptor data
   HGLOBAL hObjDesc =
            pDataObject->GetGlobalData(m_cfObjectDescriptor);
   if (hObjDesc == NULL)
   {
      if (pOffset != NULL)
         *pOffset = CSize(0, 0); // fill in defaults instead
      *pSize = CSize(0, 0);
      return FALSE;
   }
   ASSERT(hObjDesc != NULL);

   // else, got CF_OBJECTDESCRIPTOR. Lock it down and extract size.
   LPOBJECTDESCRIPTOR pObjDesc =
               (LPOBJECTDESCRIPTOR)GlobalLock(hObjDesc);
   ASSERT(pObjDesc != NULL);
   pSize->cx = (int)pObjDesc->sizel.cx;
   pSize->cy = (int)pObjDesc->sizel.cy;
   if (pOffset != NULL)
   {
      pOffset->cx = (int)pObjDesc->pointl.x;
      pOffset->cy = (int)pObjDesc->pointl.y;
   }
   GlobalUnlock(hObjDesc);
   GlobalFree(hObjDesc);

   // successfully retrieved pSize & pOffset info
   return TRUE;
}

This function calls COleDataObject::GetGlobalData and acquires the CF_OBJECTDESCRIPTOR data in a block of global memory. The function locks the memory down, reads the size attributes, and then unlocks and frees the block of memory. This function is used by OnDragEnter in the code samples in "Handling a Drag-and-Drop Operation."


Handling a Drag-and-Drop Operation

Home | Overview | How Do I

The actual work of handling a drag-and-drop operation is done by overriding four member functions defined by CView:

virtual BOOL OnDrop(COleDataObject* pDataObject,
         DROPEFFECT dropEffect, CPoint point);
virtual DROPEFFECT OnDragEnter(COleDataObject* pDataObject,
            DWORD grfKeyState, CPoint point);
virtual DROPEFFECT OnDragOver(COleDataObject* pDataObject,
            DWORD grfKeyState, CPoint point);
virtual void OnDragLeave();

These functions are called by the OLE system DLL (via the MFC framework) during a drag-and-drop operation.

The first function called during an actual drag-and-drop operation is OnDragEnter, which is called when the mouse first enters the window:

DROPEFFECT CDrawView::OnDragEnter(COleDataObject* pDataObject,
   DWORD grfKeyState, CPoint point)
{
   ASSERT(m_prevDropEffect == DROPEFFECT_NONE);
   m_bDragDataAcceptable = FALSE;
   if (!COleClientItem::CanCreateFromData( pDataObject ))
      return DROPEFFECT_NONE;

   GetObjectInfo(pDataObject, &m_dragSize, &m_dragOffset);
   CClientDC dc(NULL);
   dc.HIMETRICtoDP(&m_dragSize);
   dc.HIMETRICtoDP(&m_dragOffset);

   return OnDragOver(pDataObject, grfKeyState, point);
}

This function first checks whether the COleDataObject provided by the drop source contains data that DRAWCLI can use. If not, the function sets a flag indicating that the data is unacceptable, and returns DROPEFFECT_NONE, indicating that a drop operation would have no effect. On the other hand, if DRAWCLI can use the data, the function computes the size and position of the focus rectangle. It does this by using the GetObjectInfo helper function to get the size of the object in the COleDataObject object.

The next function called during a drag-and-drop operation is OnDragOver, which is called whenever the mouse moves within the window. This function is responsible for determining whether the window can accept the drop operation, and if so, for providing target feedback:

DROPEFFECT CDrawView::OnDragOver(COleDataObject*,
   DWORD grfKeyState, CPoint point)
{
   if (m_bDragDataAcceptable == FALSE)
      return DROPEFFECT_NONE;

   point -= m_dragOffset;  // adjust target rect by cursor offset

   // check for point outside logical area
   // GetTotalSize() returns the size passed to SetScrollSizes()
   CRect rectScroll(CPoint(0, 0), GetTotalSize());

   CRect rectItem(point,m_dragSize);
   rectItem.OffsetRect(GetDeviceScrollPosition());

   DROPEFFECT de = DROPEFFECT_NONE;
   CRect rectTemp;
   if (rectTemp.IntersectRect(rectScroll, rectItem))
   {
      // check for force link
      if ((grfKeyState & (MK_CONTROL|MK_SHIFT)) ==
         (MK_CONTROL|MK_SHIFT))
         de = DROPEFFECT_NONE; // we don’t support linking
      // check for force copy
      else if ((grfKeyState & MK_CONTROL) == MK_CONTROL)
         de = DROPEFFECT_COPY;
      // check for force move
      else if ((grfKeyState & MK_ALT) == MK_ALT)
         de = DROPEFFECT_MOVE;
      // default -- recommended action is move
      else
         de = DROPEFFECT_MOVE;
   }

   if (point == m_dragPoint)
      return de;

   // else, cursor has moved -- need to update the drag feedback
   CClientDC dc(this);
   if (m_prevDropEffect != DROPEFFECT_NONE)
   {
      // erase previous focus rect
      dc.DrawFocusRect(CRect(m_dragPoint, m_dragSize));
   }
   m_prevDropEffect = de;
   if (m_prevDropEffect != DROPEFFECT_NONE)
   {
      m_dragPoint = point;
      dc.DrawFocusRect(CRect(point, m_dragSize));
   }
   return de;
}

This function first checks the flag m_bDragDataAcceptable to see if it’s necessary to do any more processing. If so, the function then checks which, if any, keys are being depressed, determining whether the user wants a link operation, a move, or a copy. Since DRAWCLI isn’t a linking container, this function returns DROPEFFECT_NONE when a link operation is specified, meaning that the view won’t accept the dragged object. DRAWCLI does accept copy or move operations, so the function returns DROPEFFECT_COPY and DROPEFFECT_MOVE in those instances. (The drop source receives these DROPEFFECT values and modifies the mouse cursor appropriately.) Finally, if the operation is a copy or a move, the function draws the focus rectangle to indicate where the object would land if it were dropped.

If the mouse leaves the window without having dropped the object, the function that gets called is OnDragLeave. This function simply performs a little clean-up:

void CDrawView::OnDragLeave()
{
   CClientDC dc(this);
   if (m_prevDropEffect != DROPEFFECT_NONE)
   {
      // erase previous focus rect
      dc.DrawFocusRect(CRect(m_dragPoint,m_dragSize));
      m_prevDropEffect = DROPEFFECT_NONE;
   }
}

If the drag-and-drop operation was one that DRAWCLI was willing to accept, the function removes the target feedback by erasing the last focus rectangle drawn.

Finally, the function that gets called if the user actually performs the drop is OnDrop:

BOOL CDrawView::OnDrop(COleDataObject* pDataObject,
   DROPEFFECT dropEffect, CPoint point)
{
   ASSERT_VALID(this);

   // clean up focus rect
   OnDragLeave();

   // offset point as appropriate for dragging
   GetObjectInfo(pDataObject, &m_dragSize, &m_dragOffset);
   CClientDC dc(NULL);
   dc.HIMETRICtoDP(&m_dragSize);
   dc.HIMETRICtoDP(&m_dragOffset);
   point -= m_dragOffset;

   // invalidate current selection since it will be deselected
   OnUpdate(NULL, HINT_UPDATE_SELECTION, NULL);
   m_selection.RemoveAll();
   if (m_bDragDataAcceptable)
      PasteEmbedded( *pDataObject, point );

   // update the document and all views
   GetDocument()->SetModifiedFlag();
   GetDocument()->UpdateAllViews(NULL, 0, NULL);

   return TRUE;
}

This function determines the point at which the dropped object resides, deselects the currently selected object, and creates an OLE embedded object, using the COleDataObject object provided by the drop source. Note that the CDrawView::PasteEmbedded function now takes an additional parameter compared with the previous version of DRAWCLI; this parameter lets the caller specify the location of a new embedded object, something that is unnecessary for Paste operations but is useful for drag-and-drop operations.

It would also be possible to make DRAWCLI a drop source, allowing the user to drag a selection from one of DRAWCLI’s windows into another application’s. However, DRAWCLI doesn’t offer any common Clipboard formats, nor is DRAWCLI an OLE server, so there are no applications that could accept a dragged object originating from DRAWCLI. Consequently, the current version of DRAWCLI would not be a useful drop source.

For more information on MFC’s drag-and-drop support, see Drag and Drop (OLE). For more information about drag-and-drop in general, see Inside OLE or the OLE documentation on the MSDN Library CD.


Providing Summary Information

Home | Overview | How Do I

It’s recommended that, as part of its OLE support, your Windows 95 application store Summary Information with each file. This means offering a Summary Info command on your File menu, allowing the user to associate a title, keywords, or other attributes with a document. This also means using the compound file format (by calling COleDocument::EnableCompoundFile in the constructor for your document class) and writing these attributes as an OLE property set into a stream named “\005Summary Information” off the root storage of your document’s compound file. A Windows 95 user can view the Summary Information when examining the properties of a file from within the Explorer.

MFC does not currently provide classes that manage Summary Information. However, the DRAWCLI application does include a sample implementation, in the form of the class CSummInfo, which you can use as an example when implementing your own; this class is used by the document class CDrawDoc. DRAWCLI also include property pages for displaying and modifying Summary Information; the following figure shows what the interface for using Summary Information looks like.

For more information on OLE property sets in general and Summary Information in particular, see the article OLE 2.0 Property Sets Exposed on the MSDN Library CD or the appendix OLE Property Sets in the OLE documentation.

DRAWCLI’s Summary Information Property Sheet


Adding MAPI Support

Home | Overview | How Do I

Your Windows 95 application must include a Send Mail command on its File menu. The MFC library supplies an implementation of the Send Mail command in the form of two member functions of the CDocument class: OnFileSendMail and OnUpdateFileSendMail.

The OnFileSendMail member function saves the current document as an attachment to a mail message, and then invokes the mail client installed on the user’s machine; the mail client allows the user to address the mail, add text, and then send the message. The OnUpdateFileSendMail member function enables or disables the Send Mail command depending on whether MAPI support is present on the user’s machine.

Binding these functions to a menu item in DRAWCLI involves the following modifications to the source files:

  • Adding a menu item to the File menu with the command ID ID_FILE_SEND_MAIL.

  • Adding the following macros to the message map for CDrawDoc:
    ON_COMMAND(ID_FILE_SEND_MAIL, OnFileSendMail)
ON_UPDATE_COMMAND_UI(ID_FILE_SEND_MAIL, OnUpdateFileSendMail)

    These macros go outside of the special //{{AFX delimiter comments because they’re entered manually instead of through ClassWizard.

There’s no need to override these functions; their definitions in the base class are invoked if the derived class doesn’t provide new ones. For CDrawDoc, the COleDocument definitions of these functions get invoked. For a non-OLE document class, the CDocument definitions of these functions get invoked.

If you’re creating a new MFC application, you can have AppWizard add the entries listed above by checking the Add MAPI Support check box.

For more information, see the article MAPI Support in MFC.


For More Information on the Windows 95 Logo

Home | Overview | How Do I

For more information on meeting the Windows 95 logo requirements, see the paper Diving into the Requirements for the Windows 95 Logo on the MSDN Library CD.

There are a few special requirements for utilities and development tools. For details, please see the document on the Windows 95 Logo Technical Criteria, available in the locations listed below. In general, these locations will always include the most up-to-date information available on the Windows 95 logo:

  • On the Internet use ftp or the World-Wide-Web (ftp://ftp.microsoft.com/PerOpSys/Win_News, http://www.microsoft.com).

  • On The Microsoft Network, open Computers and Software, Software Companies, Microsoft, Windows 95, WinNews.

  • On CompuServe®, type GO WINNEWS.

  • On Prodigy™, JUMP WINNEWS.

  • On America Online®, use keyword WINNEWS.

  • On GEnie™, download files from the WinNews area under the Windows RTC.

You can access the Microsoft Developer Solutions Phone-Fax service by calling (800) 426-9400. Choose option 2 for Developer Solutions, then option 1 for the Faxback service; or dial (425) 635-2222. You can request a complete index of available documents. Documents on the Windows Logo are numbered in the 130s range.

You can also get answers to logo-related questions or request a pre-testing kit from the Windows Logo Department:

by e-mail: | “winlogo@microsoft.com”
by fax: | (425) 936-7329, Attn: Windows Logo Department
by phone: | (425) 936-8220
by mail: | Microsoft Corporation Attn: Windows Logo Department, Bldg. 20 Redmond, WA 98052-6399


Working with Classes Topics

Home | Overview | How Do I | Tutorial

For an overview of the ClassWizard, WizardBar, and ClassView tools that accompany Visual C++, see Overview. The present article provides detailed coverage of these tools.

Articles in this family include general articles on using ClassWizard, WizardBar, and ClassView and more specialized articles on accomplishing specific tasks with these tools.

Which tools do you want to know more about?

  • Using ClassView

  • Using WizardBar

  • Using ClassWizard

Working with classes articles

  • Adding a Class

  • Adding a Member Function

  • Adding a Member Variable

  • Overriding a Virtual Function

  • Adding a Message Handler

  • Navigating the Class Structure

  • Deleting a Member Function

ClassWizard-specific articles

  • Classes Offered by ClassWizard

  • Working with Existing Classes and Type Libraries

  • Mapping Messages to Functions

  • Working with Dialog Box Data

  • Keeping ClassWizard Updated When Code Changes

  • ClassWizard: Special-Format Comment Sections

  • ClassWizard: Tips and Troubleshooting

Database articles:

  • ClassWizard: Database Support

  • ClassWizard: Creating a Recordset Class

  • ClassWizard: Binding Recordset Fields to Table Columns

  • ClassWizard: Creating a Database Form

  • ClassWizard: Mapping Form Controls to Recordset Fields

  • ClassWizard: Foreign Objects

Automation articles:

  • ClassWizard: Automation Support

  • ClassWizard: Adding Automation Properties and Methods

  • ClassWizard: Accessing Automation Servers


Using ClassView

Home | Overview | How Do I | Tutorial

ClassView shows all the C++ classes for which definitions are available, and the members of those classes. Double-click on a class icon (or click the + symbol beside the icon) to expand the class and display its members.

ClassView uses icons to represent classes, class members, and other items in the project. The following table shows the icons and their meanings:

Icon | Meaning
 | Class
 | Protected member function
 | Private member function
 | Public member function
 | Protected member variable
 | Private member variable
 | Public member variable
 | Interface
 | Method (for a COM object)
 | Property (for a COM object)
 | Dialog

Visual C++ derives the contents of the ClassView pane using a dynamic parser that scans the source files included in the project workspace. When you type in a new class, variable, or member function, ClassView and WizardBar are now automatically updated without saving.

The relationships in ClassView are logical relationships, not physical relationships, according to the defined class structure. ClassView displays C++ classes for which definitions according to the ANSI standard are available, and the members of those classes. For example, the following code provides both a declaration and a definition for class MyClass, its constructor, and a function, MyFunc(). The class and its two member functions will appear in ClassView.

class MyClass
{
public:
   MyClass();
   void MyFunc(void);
};

For a member to appear in the ClassView list, it must be declared in a header file included in the project.

See Adding a Class for the implications of defining classes and members without the use of the Visual C++ New Class feature.

In ClassView, you can:

  • Add a new class to the project.

  • Add a new ATL object to the project (MFC or ATL).

  • Add a new form to the project.

  • Add member functions to the selected class.

  • Delete a member function from the selected class.

  • Add member variables to the selected class.

  • Add a virtual function that overrides a virtual function in the base class.

  • Add a message handler for the selected class.

  • Add a new interface to an existing ATL object or control

  • Add a connection point to an ATL object

  • Add a method to an interface or non-MFC Dispinterface

  • Go to the definition of a class or member.

  • Go to the references to a class or member.

  • Display derived class or base class graphs.

  • Reuse a class by storing it in the Gallery for later use in other projects.

  • Set a breakpoint on a member function.

  • Group class members by access specifier or alphabetically.

  • Add a method to a COM interface.

  • Add a property to a COM interface.

  • Add an event to an ActiveX control.

  • Create new folders in the project workspace.

  • View properties of classes and their members.

See Also Using WizardBar, Using ClassWizard


Browsing Symbols from ClassView

Home | Overview | How Do I | Tutorial

From ClassView, you can get information about the use of the classes, functions, and variable symbols in your application. You can select a symbol, then automatically open that source file to the definition or declaration of the symbol, or find references to those symbols in your application's source files.

To find a definition or declaration

  1. Select the symbol (class, function, or variable) for which you want to find the definition or declaration.

  2. With the mouse pointer over the selected symbol, click the right mouse button to display the shortcut menu, and click Go To Definition or Go To Declaration, as applicable.

    -or-

    Double-click the name of the symbol.

Visual C++ opens a text editor window and displays the source file containing the definition or declaration, with the insertion point positioned there.

Note Visual C++ computes the contents of ClassView as a background process. This may mean that there is some delay from the time you open a project or save a revised file until the view is computed, and you can find a definition or declaration. If you are completing other processes that use significant computing resources, the delay may increase.

To find references

  1. Select the symbol for which you want to find references.

  2. With the mouse pointer over the selected class, click the right mouse button to display the shortcut menu, and click References.

    Note If you have not built your application with the option to build a browse information file, a message box appears, asking if you want to build the browse information file. If you click Yes, it builds the browse information file, and you can then find references. If you click No, the references are not available.

The Definitions And References browse information window appears, with the symbol that you chose selected.

To group members in a class

You can group the members in a class either alphabetically by name or alphabetically in access specifier groups — that is, private, protected, or public.

  1. Select a class node.

  2. Click the right mouse button to display the shortcut menu.

  3. Click Group By Access to toggle the grouping.

    If the command has a check, the members are already grouped by access specifier; if not, they are grouped alphabetically.

See Also Displaying Graphs from ClassView, Setting Breakpoints in ClassView


Displaying Graphs from ClassView

Home | Overview | How Do I | Tutorial

From ClassView, you can display graphs showing the class derivations and the function-calling order in your application.

Note If you have not built your application with the option to build the browse information file, a message box appears, asking if you want to build the browse information file. If you click Yes, it builds the browse information file, and you can then find references. If you click No, the references are not available. Building a browse information file increases your build times.

To display a class graph

  1. Select the class for which you want to display a graph.

  2. With the mouse pointer over the selected class, click the right mouse button to display the shortcut menu, and click Base Classes to display a graph of the derivation for this class, or Derived Classes to display a graph of classes derived from this class.

The browse information window appears, with a graph for the class that you chose.

To display a call graph

  1. Select the function for which you want to display a graph.

  2. With the mouse pointer over the selected class, click the right mouse button to display the shortcut menu, and click Calls to display a graph of the functions that this function calls, or Called By to display a graph of functions that call this function.

The browse information window appears, with a graph for the function that you chose.

See Also Browsing Symbols from ClassView, Setting Breakpoints in ClassView


Setting Breakpoints in ClassView

Home | Overview | How Do I | Tutorial

From ClassView, you can quickly set breakpoints on the definition of member functions for use in the integrated debugger. Function breakpoints appear in the Breakpoints dialog (obtained by selecting Breakpoints from the Edit menu).

To set a function breakpoint

  • From ClassView, right-click a member function, and from the shortcut menu select Set Breakpoint.

ClassView cannot set line number breakpoints. Line number breakpoints appear in the Breakpoints dialog and as glyphs in the text editor window.

To set a line number breakpoint

  • From ClassView, double-click a member function to navigate to its definition in a text editor window, then press F9. (Or from the Build MiniBar, click Insert/Remove Breakpoint.) The breakpoint glyph (red dot) appears in the left-hand margin of the text editor window.

See Also Browsing Symbols from ClassView, Displaying Graphs from ClassView


Using WizardBar

Home | Overview | How Do I | Tutorial

The Universal WizardBar is a dockable toolbar that provides convenient access to ClassWizard and ClassView functionality. You use WizardBar to navigate through and perform actions on classes.

WizardBar tracks the current context. At any given time, it displays the most relevant information about the location of the focus in a project. For example, when you are working in the source editor window, WizardBar displays the class or member function in which the cursor is placed. However, by selecting a class or member function from the WizardBar menus, you can navigate through the class structure as you do with ClassView.

WizardBar tracks all class declarations, including those for empty classes that do not yet contain any members. If your cursor is in such a class declaration, the Classes drop-down list displays the class name, the Filters drop-down list displays "(All Class Members)", and the Members drop-down list displays the message "No members — Create C/C++ Member Function." Adding a new member function is the default action for empty classes. Choosing this default action displays the Add Member Function dialog box, which you can use to define a stub function.

For more information on WizardBar interface and context tracking, see Overview: The Universal WizardBar.

WizardBar also provides a menu of actions that comprise the most common navigation and editing tasks you would perform on classes.

With WizardBar's Action menu, you can:

  • Go to a function definition (implementation)

  • Go to a function declaration

  • Go to a class definition

  • Add a windows message handler

  • Add a virtual function

  • Add a member function

  • Delete a member function

  • Add a new class

  • Add a new form

  • Go to the next function in a file

  • Go to the previous function in a file

  • Open an include file

  • Get help on WizardBar

Note that the WizardBar is language-independent; however, this section discusses only its operation with C++ classes.

What do you want to do?

  • Access WizardBar

  • Navigate to code

  • Add a class or function

  • Obtain help on WizardBar

See Also Adding a Member Variable, Overriding a Virtual Function, Deleting a Member Function, Navigating the Class Structure


Accessing WizardBar

Home | Overview | How Do I | Tutorial

To view the WizardBar, right-click on an empty (unused) portion of the toolbar area, and select WizardBar from the menu. By default the docked WizardBar appears in the toolbar area.

To undock the WizardBar, double-click the double bar on the far left edge of the toolbar. To redock, double-click on the title bar of the undocked toolbar. The docked and undocked versions of the toolbar are shown below:

WizardBar, Docked

WizardBar, Undocked

As shown in the preceding figures, the WizardBar has the following controls:

  • a Class drop-down list, which displays the classes in the project

  • a Filter drop-down list, which specifies the class members to list in the Members drop-down list

  • a Members drop-down list, which displays the members of the selected class

  • an Action button, which when clicked executes the default action (the default action depends on the WizardBar's current context)

  • an Action menu, which is a drop-down menu listing all the tasks the WizardBar can currently perform

For a complete description of WizardBar controls, see Overview: The Universal WizardBar.


WizardBar Navigation

Home | Overview | How Do I | Tutorial

WizardBar performs the same kind of navigation tasks as ClassView. You can open application files in the text editor by selecting classes and member functions.

Go To Function Declaration

Selecting this action navigates to the location in the header or implementation file in which the selected member function is declared.

This is the default action, that is, what happens when you click the Action button without selecting any menu items. Subsequent clicks on the Action button toggle between the function declaration and the function definition.

Go To Function Definition

Selecting this action navigates to the location in the implementation file in which the selected member function is defined. (This is the same as double-clicking a member function in ClassView.)

See WizardBar Context Tracking for more information.

Go To Class Definition

Selecting this action navigates to the location in which the selected class is declared in a header or implementation file. (To go to a different class declaration, select another class from the Class drop-down list and click the Action button.)

Go To Next Function

Selecting this action navigates to the next function in the file. If you have reached the last function in the file, the search starts again at the beginning of the file.

Go To Previous Function

Selecting this action navigates to the previous function in the file. If you have reached the first function in the file, the search starts again at the end of the file.

Open Include File

Selecting this action allows you to open header files associated with the current file. When you select this action, a dialog box prompts you to select a header file to open.


WizardBar Context Tracking

Home | Overview | How Do I | Tutorial

WizardBar passively tracks the current context of the focus in a project. It displays or attempts to display relevant information about the location in which you are currently working in a project.

When you work in a source editor window, WizardBar displays the class or member function in which the cursor is placed. In the source editor, a function effectively begins at the home location (left hand side) of the line on which its definition or declaration begins, and ends with the } end bracket. When the cursor is "between" functions, that is, after an end bracket but before the next function is defined, WizardBar displays the previous function name in a shaded font.

WizardBar also tracks the current context when you work in the dialog editor. WizardBar tracks the class of the selected dialog, or the control ID of the selected control, depending on which is currently active. Double-clicking a dialog control does one of the following:

  • For dialogs that have not yet been associated with a class, ClassWizard appears along with an Adding a Class dialog box, which prompts you to provide a class for the new resource. You can either create a new class or select an existing class.

  • For controls for which a message handler is already implemented, you navigate directly to that handler's definition. (If more than one handler is implemented for the control, you navigate to the first handler in alphanumeric order.)

  • For controls with no handler currently implemented, the Add Member Function dialog box opens. The focus is on the default message for that particular control, for example, BN_CLICKED for a push button. Selecting a message and then OK creates a stub message handler that you can implement later by providing the handler code.

  • For more information about default events for controls, see the Default Controls Event Table.

In other editors, WizardBar does not track, but retains its most recent context displayed in a shaded font.

WizardBar also adjusts its Action menu to include only tasks that make sense within the current context. The Action button has two states: active and inactive. In the active state the button is lit with a yellow document under the wand, to show that the WizardBar can perform some meaningful action. In the inactive state the document disappears, indicating that the WizardBar cannot currently perform a valid action.

The default action, invoked by clicking the Action button, also depends on the current context. It can be "go to function definition," "go to function declaration," or "create new class," depending on the focus. You execute the default action by:

  • clicking the Action button

  • selecting an item in any drop-down list and pressing ENTER

  • selecting a bold item in any drop-down list

  • selecting an element from the Members drop-down list


Creating or Deleting Classes and Functions

Home | Overview | How Do I | Tutorial

WizardBar performs some of the tasks that ClassWizard does, as well as some that ClassWizard does not, such as creating a new form. You access the functionality described below from the Action menu, which opens when you click the down arrow at the right end of the WizardBar.

Add Windows Message Handler

Selecting this action adds a Windows message handler function to the selected class.

For details on how to add a Windows message handler, see Adding a Message Handler.

Add Virtual Function Override

Selecting this action adds to the selected class a new member function that overrides one of the MFC virtual functions.

For details on how to add a virtual function override, see Overriding a Virtual Function.

Add Member Function

Selecting this action adds a new member function to the selected class.

For details on how to add a member function, see Adding a Member Function.

Delete Member Function

Selecting this action removes the member function declaration and comments out the function body, if one exists. It also removes associated entries in the MSG, MESSAGE and DISPATCH maps.

For details on how to remove a member function, see Deleting a Member Function.

New Class

Selecting this action creates a new MFC, ATL, or generic class. The New Class dialog box appears, in which you specify the class name and the base class. It creates a header file and an implementation file for the class.

For details on how to add a class, see Adding a Class.

New Form

Selecting this action creates a new form, and, for applications based on the document/view architecture, an associated document template. The New Form dialog box appears, in which you specify the form name and base view class, as well as any document template information.

For details on how to add a form, see Adding a Form.


WizardBar Help

Home | Overview | How Do I | Tutorial

Selecting WizardBar Help opens the online Help topic Overview: The Universal WizardBar.


Using ClassWizard

Home | Overview | How Do I | Tutorial

ClassWizard is like a programmer's assistant: it makes it easier for you to do certain routine tasks such as creating new classes, defining message handlers, overriding MFC virtual functions, and gathering data from controls in a dialog box, form view, or record view.

It is important to note that ClassWizard works only with applications that use MFC classes, unlike ClassView and WizardBar, which work with MFC, ATL, or Generic (user-defined) classes.

Also, ClassView does not recognize classes unless they are registered in the ClassWizard database (.clw) file.

With ClassWizard, you can:

  • Create new classes derived from many of the main framework base classes that handle Windows messages and recordsets.

  • Map messages to functions associated with windows, dialog boxes, controls, menu items, and accelerators.

  • Create new message-handling member functions.

  • Delete message-handling member functions.

  • See which messages have message handlers already defined and jump to the handler program code.

  • Define member variables that automatically initialize, gather, and validate data entered into dialog boxes or form views.

  • Add Automation methods and properties when creating a new class

  • Work with Existing Classes and Type Libraries

What do you want to know more about?

  • Classes Offered by ClassWizard

  • ClassWizard: Special-Format Comment Sections

  • Keeping ClassWizard Updated When Code Changes

  • ClassWizard: Tips and Troubleshooting

  • ClassWizard: Database Support

  • ClassWizard: Automation Support

See Also Adding a Class, Adding a Member Function, Adding a Member Variable, Overriding a Virtual Function, Adding a Message Handler, Deleting a Member Function, Navigating the Class Structure


Classes Offered by ClassWizard

Home | Overview | How Do I | Tutorial

ClassWizard only supports MFC (Microsoft Foundation Classes). This means that it can recognize and create only classes that are derived from the MFC classes shown in the table below.

Types of MFC Classes Available from ClassWizard

Class | Description
CAnimateCtrl | Provides the functionality of the Windows common animation control.
CasyncMonikerFile | Provides functionality for the use of asynchronous monikers in ActiveX controls (formerly OLE controls).
CAsyncSocket | Represents a Windows Socket (an endpoint of network communication).
CButton | Button control.
CcachedDataPathProperty | Implements an ActiveX control property transferred asynchronously and cached in a memory file.
CCmdTarget | Base class for objects that can receive and respond to messages. It is the result of a selection based on a table query.
CColorDialog | Color-selection dialog box with a list of colors that are defined for the display system.
CComboBox | Combination text box/list box with static or edit control.
CDaoRecordSet | Represents a set of records selected from a data source. CdaoRecordset objects are available in three forms: table-type recordsets, dynaset-type recordsets, and snapshot-type recordsets.
CDaoRecordView | Displays database records in controls. This form view is directly connected to a CDaoRecordset object.
CDataPathProperty | Implements an ActiveX control property that can be loaded asynchronously.
CDialog | Dialog box.
CDocument | Class for managing program data.
CEdit | Rectangular child window for text entry.
CEditView | Provides the functionality of a Windows edit control and can be used to implement simple text-editor functionality.
CFileDialog | Windows common file dialog box provides an easy way to implement File Open and File Save As dialog boxes.
CFontDialog | Font-selection dialog box that displays a list of fonts that are currently installed in the system.
CFormView | Window that can contain dialog box controls.
CFrameWnd | Single document interface (SDI) frame window.
CHeaderCtrl | Provides the functionality of the Windows common header control.
CHotKeyCtrl | Provides the functionality of the Windows common hot key control.
CHttpFilter | Creates and manages a Hypertext Transfer Protocol (HTTP) filter object.
CHttpServer | Provides a means of extending the functionality of an ISAPI-compliant HTTP server. Wraps ISAPI functionality and processes client requests including extension DLLs but excluding CGI executables.
CListBox | List box.
CListCtrl | Provides the functionality of the Windows common list view control.
CListView | List control that simplifies use of CListCtrl, the class that encapsulates list-control functionality.
CMDIChildWnd | Multiple document interface (MDI) child frame window.
COleDocument | Treats a document as a collection of CDocItem objects to handle OLE items. Both container and server applications require this architecture because their documents must be able to contain OLE items.
COleLinkingDoc | Base class for OLE container documents that support linking to the embedded items they contain.
COleServerDoc | Base class for OLE server documents.
COleServerItem | Provides the server interface to OLE items.
CPrintDialog | Windows common dialog box for printing that provides an easy way to implement Print and Print Setup dialog boxes.
CProgressCtrl | Provides the functionality of the Windows common progress bar control.
CPropertyPage | Represents an individual page of a property sheet, otherwise known as a tab dialog box.
CPropertySheet | Represents property sheets, otherwise known as tab dialog boxes. A property sheet consists of a CPropertySheet object and one or more CPropertyPage objects.
CRecordset | Class for accessing a database table or query.
CRecordView | Window containing dialog box controls mapped to recordset fields.
CRichEditCtrl | Window in which the user can enter and edit text. The text can be assigned character and paragraph formatting, and can include embedded objects.
CRichEditView | Maintains the text and formatting characteristics of text.
CScrollBar | Scroll bar.
CScrollView | Scrolling window, derived from CView.
CSliderCtrl | Provides a window containing a slider and optional tick marks.
CSocket | Works with classes CSocketFile and CArchive to manage the sending and receiving of data.
CSpinButtonCtrl | Provides a pair of arrow buttons that the user can click to increment or decrement a value.
CStatic | A simple text field, box, or rectangle used to label, box, or separate other controls.
CStatusBarCtrl | Provides a horizontal window, usually displayed at the bottom of a parent window, in which an application can display status information.
CTabCtrl | Allows an application to display multiple pages in the same area of a window or dialog box.
CToolBarCtrl | Provides the functionality of the Windows toolbar common control.
CToolTipCtrl | Provides the functionality of a "tooltip control," a small popup window that displays a single line of text describing the purpose of a tool in an application.
CTreeCtrl | Displays a hierarchical list of items.
CTreeView | Tree control that simplifies use of CTreeCtrl, the class that encapsulates tree-control functionality.
CView | Class for displaying program data.
CWinThread | Represents a thread of execution within an application.
generic CWnd | Custom window.
splitter | An MDI child window that contains a CSplitterWnd class. The user can split the resulting window into multiple panes.


ClassWizard: Special-Format Comment Sections

Home | Overview | How Do I | Tutorial

This article explains where and how ClassWizard edits your source files.

When you add a new class using ClassWizard, special-format comments are placed in your code to mark the sections of the header and implementation files that ClassWizard edits. ClassWizard never modifies code that is outside these commented sections.

ClassWizard creates the following types of comments in your code:

  • Message-Map Comments

  • Virtual Function Comments

  • Data Map Comments

  • Field Map Comments

  • Active Dispatch Map Comments

Message-Map Comments

For most classes, there are two related sections of code that ClassWizard edits: the member-function definitions in the class header file and the message-map entries in the class implementation file.

The ClassWizard comments in the header file look like this:

//{{AFX_MSG(<classname>)
  afx_msg void OnAppAbout();
//}}AFX_MSG

The ClassWizard section in the implementation file is set off with comments that look like this:

//{{AFX_MSG_MAP(<classname>)
  ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
//}}AFX_MSG_MAP

The notes in the ClassWizard section act as placeholders. ClassWizard removes the note from any ClassWizard section in which it writes code.

Virtual Function Comments

As with message handlers, ClassWizard writes code to two locations when you use it to override a virtual function in one of your classes.

The ClassWizard comments in the header file look like the following example for virtual function overrides:

//{{AFX_VIRTUAL(<classname>)
  virtual BOOL InitInstance();
//}}AFX_VIRTUAL

The ClassWizard section in the implementation file has no special comments. Virtual function definitions in the .cpp file look like other function definitions.

Data Map Comments

For dialog boxes, form views, and record views, ClassWizard creates and edits three other sections that are marked with special format comments:

  • Member variable declarations in the class header file:
    //{{AFX_DATA
..
//}}AFX_DATA
  • Member variable initialization in the class implementation file:
    //{{AFX_DATA_INIT
..
//}}AFX_DATA_INIT
  • Data-exchange macros in the implementation file:
    //{{AFX_DATA_MAP
..
//}}AFX_DATA_MAP

Field Map Comments

For record field exchange, ClassWizard creates and edits three other sections that are marked with special format comments:

  • Member variable declarations in the class header file:
    //{{AFX_FIELD
..
//}}AFX_FIELD
  • Record exchange function calls in the implementation file:
    //{{AFX_FIELD_MAP
..
//}}AFX_FIELD_MAP
  • Member variable initializations in the class header file:
    //{{AFX_FIELD_INIT
..
//}}AFX_FIELD_INIT

Active Dispatch Map Comments

For Active method dispatch, ClassWizard creates and edits four other sections that are marked with special format comments:

  • Active events in the class header file:
    //{{AFX_EVENT
..
//}}AFX_EVENT
  • Active events in the class implementation file:
    //{{AFX_EVENT_MAP
..
//}}AFX_EVENT_MAP
  • Automation declarations in the class header file:
    //{{AFX_DISP
..
//}}AFX_DISP
  • Automation mapping in the class implementation file:
    //{{AFX_DISP_MAP
..
//}}AFX_DISP_MAP

For more information see Working with Dialog Box Data.


Working with Existing Classes and Type Libraries

Home | Overview | How Do I | Tutorial

In addition to letting you create new classes (of certain types), ClassWizard works with existing classes (of certain types) and with type library information. The following articles discuss these options:

  • Importing a Class into ClassWizard

  • Associate an Existing Class with a Resource

  • Importing the Elements of a Type Library


Importing a Class into ClassWizard

Home | Overview | How Do I | Tutorial

In previous releases of Visual C++ it was necessary to import classes into your project so that ClassWizard could recognize them. This is no longer necessary.

If you want to use code from another project, there are two simple methods of doing so:

  • Insert the other project into the workspace

  • Insert components or controls from the Gallery into the active project

Inserting another project into the workspace

Open the project you want to work on, then, on the Project menu, click Insert Project into Workspace. This inserts the other project in its entirety into the workspace. All the code in the other project is then made available to the first project. ClassWizard displays the classes from the project selected in the Project drop-down list.

Inserting components or controls from the Gallery

You must first store the class to be shared in the Gallery. To do so, go to the project containing the class to be shared, right-click the class in ClassView and on the shortcut menu click Add to Gallery. This stores the class as a component in the Gallery directory.

Open the project to which you want to add the class. On the Project menu, point to Add To Project, then click Components and Controls to open the Gallery. Select the class you previously stored there and insert it into the active project.

Note If the new code you copy was not created by a Visual C++ wizard, you may have to rebuild the ClassWizard (.clw) file in order that ClassWizard can recognize it. See Rebuilding the ClassWizard (.clw) File. If the code you are importing does not already have wizard-generated comments in it, manually add the special-format comments the wizard uses to locate message-map entries. For more information on wizard-generated special-format comments, see MFC Technical Note 6.


Associate an Existing Class with a Resource

Home | Overview | How Do I | Tutorial

Use the Select Class dialog box to associate a new dialog box, menu, toolbar, or accelerator resource with an existing class. You will use this dialog box if you created a class before you created the resource that the class should be associated with. The association makes the resource command IDs available for mapping when the class is selected in the ClassWizard Message Maps tab or in WizardBar.

Note You can work more efficiently if you first create a resource and then use ClassWizard to associate a class with the resource.

To associate an existing class from the project with a resource

  1. Use the dialog, menu, toolbar, or accelerator editor to create a resource. For information on using these editors, see Resource Editor Topics (Specific to Visual C++).

  2. Double-click on the resource.

    ClassWizard appears, along with an Adding a Class dialog box, which prompts you to provide a class for the new resource. You can either create a new class or select an existing class.

  3. Click the button to select an existing class.

    The Select Class dialog appears, displaying a list of existing classes in the active project.

  4. Select a class from the list, then click the Select button.

    A message box asks if you want to substitute the resource ID for the class's current resource ID.

  5. Click OK.

    ClassWizard associates the resource with the specified class.


Importing the Elements of a Type Library

Home | Overview | How Do I | Tutorial

You can use ClassWizard to wrap the elements of a type library in an MFC C++ class and add the new class to a project. A type library is a collection of controls that you either purchase or write yourself. ClassView can only view valid type libraries.

To import the elements of a type library

  1. On the View menu, click ClassWizard.

    ClassWizard appears.

  2. On any of ClassWizard's tabs, click Add Class, then click From a type library.

    The Import from Type Library dialog box appears.

  3. Select a type library and click Open.

    The Confirm Classes dialog box appears. This dialog box contains a list of classes that ClassWizard can create from information in the type library. The class names are generated by ClassWizard.

  4. Use the Name text box to rename the class that is currently selected from the list.

  5. Use the Header File and Implementation File text boxes to rename the .h and .cpp files, if you choose to. Also, you can use the Browse buttons to rename the files or cause the files to be generated in a different directory.

    All classes selected from the class list are added to these two files.

  6. Click OK.

    ClassWizard generates the specified class.


Working with Dialog Box Data

Home | Overview | How Do I | Tutorial

ClassWizard offers an easy way to take advantage of the dialog data exchange (DDX) and dialog data validation (DDV) capabilities of MFC.

To use DDX, you define member variables in the dialog box, form view, or record view class, and associate each of them with a dialog box control. The framework transfers any initial values to the controls when the dialog box is displayed. When you click OK, it updates the variables with the data that you entered.

With DDV, dialog box information entered by the user is validated automatically. You can set the validation boundaries: the maximum length for string values in an edit-box control or the minimum or maximum numeric values when you expect a number to be entered. You can also use ClassWizard to connect dialog box controls to your own custom data-validation routines.

What do you want to know more about?

  • ClassWizard and Dialog Data Exchange

  • ClassWizard and Dialog Data Validation

  • Custom Data Exchange and Validation


ClassWizard and Dialog Data Exchange

Home | Overview | How Do I | Tutorial

ClassWizard lets you create variables that use the framework's automatic dialog data exchange (DDX) capabilities. When you want to set an initial value for or gather data from a dialog box control, use ClassWizard to define a data member in the dialog box class. The framework then transfers the initial value of the variable to the dialog box when it is created and updates the associated member variable when the dialog box is dismissed.

Note You can also use CWnd::UpdateData to transfer data back and forth between controls and member variables while a dialog box is open.

Note ClassWizard does not support COleDBRecordView, so you cannot use ClassWizard to do the databinding (message maps) in an OLE DB application.

To databind the controls in an OLE DB application, use dialog data exchange (DDX) data calls with COleDBRecordView just as you would with any other MFC class. You will need to add lines to the recordset file such as:

DDX_Text(IDC_EDIT1, m_pSet->m_nFoo) // if it's a LONG

-or-

DDX_Text(IDC_EDIT1, m_pSet->m_szFoo, 50) // If it's a char 50 array

The databinding technique is illustrated in the MFCRows sample.

What do you want to know more about?

  • Defining Member Variables for DDX

  • Setting Initial Values for DDX Member Variables

  • Variable Types for the DDX Value Property

  • Variable Types for the DDX Control Property


Defining Member Variables for DDX

Home | Overview | How Do I | Tutorial

You can use ClassWizard to define member variables for dialog box controls.

To define data members for dialog data exchange

  1. Create your dialog box, place in it the controls you want, and set the appropriate control styles in the Properties window. Then use ClassWizard to define a new dialog box class. For more information, see Adding a Class.

  2. On the View menu, click ClassWizard. In ClassWizard, click the Member Variables tab.

    Note For a recordset class, Update Columns updates the current static list with the current database list. Members assigned to a deleted column may be deleted.

    The Bind All command creates an initial recordset with a default member name for every column in the table.

  3. In the Control IDs box, select the control for which you want to set up dialog data exchange (DDX), and click Add Variable.

    The Add Member Variable dialog box appears.

  4. In the Member Variable Name box, type the name of the new variable. ClassWizard provides the m_ prefix to identify it as a member variable.

  5. In the Category box, select whether this variable is a Value variable or a Control variable.

    For standard Windows controls, click Value to create a variable that contains the control's text or status as typed by the user. The framework automatically converts the control's data to the data type selected in the Variable Type box (see the table in What Are the Variable Types for the DDX Control Property?).

    You can also choose Control in the Category drop-down list to create a Control variable that gives you access to the control itself (see the table in What Are the Variable Types for the DDX Control Property?).

  6. In the Variable type box, choose from a list of variable types appropriate to the control (see the tables in What Are the Variable Types for the DDX Value Property? and in What Are the Variable Types for the DDX Control Property?).

  7. Click OK.

    The new member variable is added to the Control IDs list.

Once you have defined a DDX Value variable for a standard Windows control, the framework automatically initializes and updates the variable for you.

You can now use ClassWizard to bind a member variable to the value of a scroll-bar control, using the Value property and the int data type, as well as to a CScrollBar object, using the Control property. The Value property binds the value of a scroll-bar control (the position of the scroll box, or "thumb"). ClassWizard enables DDX for a scroll bar by calling DDX_Scroll in your DoDataExchange override.

If your DoDataExchange function contains a call to DDX_Scroll, you must additionally set the scroll-bar range before that call, as shown in the following code:

void CMyDlg::DoDataExchange( CDataExchange* pDX )
{
    CScrollBar* pScrollBar = (CScrollBar*)GetDlgItem( IDC_SCROLLBAR1 );
    pScrollBar->SetScrollRange( 0, 100 );
    CDialog::DoDataExchange( pDX );
    //{{AFX_DATA_MAP(CMyDlg)
    DDX_Scroll(pDX, IDC_SCROLLBAR1, m_nScroll );
    //}}AFX_DATA_MAP
}


What Are the Variable Types for the DDX Value Property?

Home | Overview | How Do I | Tutorial

The following table shows the type of DDX Value variables ClassWizard initially provides. To create additional variable types, see MFC Technical Note 26.

DDX Variable Types for the Value Property

Control | Variable type
Edit box | CString, int, UINT, long, DWORD, float, double, short, BOOL, COleDateTime, ColeCurrency
Normal check box | BOOL
Three-state check box | int
Radio button (first in group) | int
Nonsorted list box | Cstring, int
Drop-down list | Cstring, int
All other list box and drop-down list types | Cstring

The following additional notes apply to using DDX Value variables:

  • Possible values for three-state check boxes are 0 (off), 1 (on), and 2 (indeterminate).

  • Values for a group of radio buttons range from 0 for the first button in the group to n–1 for a group with n buttons. A value of –1 indicates that no buttons are selected.

  • When you are using a group of check boxes or radio buttons with a DDX variable, set the Auto property from each control's Property window.

  • Set the Group property for the first radio button in a group, and make sure all the other radio buttons immediately follow the first button in the tab order.

  • To use an integer value with a drop-down list or list box, turn off the Sort property found on each control's Property window Styles tab.


What Are the Variable Types for the DDX Control Property?

Home | Overview | How Do I | Tutorial

The following table shows the type of DDX Control variables you can define with ClassWizard.

DDX Variable Types Defined with the Control Property

Control | Variable type
Edit box | Cedit
Check box | Cbutton
Radio button | Cbutton
Pushbutton | Cbutton
List box | ClistBox
Drop-down list or drop-down list | CcomboBox
Static text | Cstatic
Scroll bar | CscrollBar


Setting Initial Values for DDX Member Variables

Home | Overview | How Do I | Tutorial

You can set the initial value of dialog data exchange (DDX) variables by editing the initialization code that ClassWizard places in the constructor for the dialog box class. (ClassWizard does not disturb these initialization statements once they are put in place.) The framework transfers the values to the dialog box when it is created.

Note that you can also set initial values for DDX variables after your dialog class object has been constructed, but before DoModal or CreateDialog is called.

To see what the user typed once the dialog box is dismissed, access the values of the DDX variables just as you would any other C++ member variable.


ClassWizard and Dialog Data Validation

Home | Overview | How Do I | Tutorial

By default, ClassWizard supports the types of dialog data validation (DDV) shown in the following table, but you can add additional types (see MFC Technical Note 26.

DDV Variable Types

Variable type | Data validation
Cstring | Maximum length
Numeric (int, UINT, long, DWORD, float, double) | Minimum value, maximum value

You can define the maximum length for a CString DDX variable or the minimum or maximum values for a numeric DDX variable at the time you create it.

At run time, if the value entered by the user exceeds the range you specify, the framework automatically displays a message box asking the user to reenter the value. The validation of DDX variables takes place all at once when the user clicks OK to accept the entries in the dialog box.


Custom Data Exchange and Validation

Home | Overview | How Do I | Tutorial

Although you can write a dialog box class that gathers and validates its own dialog box data using custom message handlers, you may find that you have routines for data exchange and validation (containing your own variable types and data formats) that you want to use repeatedly. You can extend the ClassWizard user interface to reuse your own DDX and DDV routines. For more information on this subject, see MFC Technical Note 26.


Keeping ClassWizard Updated When Code Changes

Home | Overview | How Do I | Tutorial

As your program develops, it's very likely that you'll need to delete or modify classes, delete or add resources, or move a class from one source file to another. ClassWizard will track your code as you make these changes: it asks you for the updated information when you next edit the affected class.

ClassWizard stores the information about your project's classes in a file with the file extension .clw. To accommodate source files that have changed, ClassWizard displays the Repair Class Information dialog box whenever it finds that the information in the .clw file is out of date.

The Repair Class Information dialog box has two main functions:

  • Deleting obsolete classes from the ClassWizard file

  • Updating the ClassWizard file with the new name or location of classes that you have changed or moved

What do you want to know more about?

  • Deleting Classes

  • Renaming or Moving Classes

  • Rebuilding the ClassWizard (.clw) File


Deleting Classes

Home | Overview | How Do I | Tutorial

To delete a ClassWizard-created class from your project, you can either delete it from the header (.h) and implementation (.cpp) files in which it coexists with other classes or delete the .h and .cpp files altogether. In either case, you must update the information in the ClassWizard (.clw) file.

To delete a class

  1. Delete all references to the class from its .h and .cpp files or delete the files from the disk.

  2. On the View menu, click ClassWizard.

    If ClassWizard appears, the active project does not contain the deleted class.

  3. From ClassWizard's Project drop-down list, select the project that contains the deleted class.

  4. If ClassWizard asks you to close any files, close ClassWizard, close the files, and then restart ClassWizard.

    A message box informs you that ClassWizard cannot find the deleted class.

  5. Click OK.

    ClassWizard displays the Repair Class Information dialog box.

  6. Click Remove.

    The class is deleted from the .clw file.

    ClassWizard appears.

  7. Click OK.

See Also Keeping ClassWizard Updated When Code Changes, Renaming or Moving Classes, Rebuilding the ClassWizard (.clw) File


Renaming or Moving Classes

Home | Overview | How Do I | Tutorial

When you change the name of a class or move it from one implementation file to another, you're prompted to update the information in the ClassWizard (.clw) file the next time you start ClassWizard.

To change the name of a class or move it from one file to another

  1. Make the desired changes to your source files.

    Note When you change the name of a class, remember to change it everywhere, including in the special-format comments ClassWizard uses. For example:

    //{{AFX_MSG_MAP(OldClass) becomes //{{AFX_MSG_MAP(NewClass)
  2. On the View menu, click ClassWizard.

    If ClassWizard appears, the active project does not contain the renamed or moved class.

  3. From ClassWizard's Project drop-down list, select the project that contains the renamed or moved class.

  4. If ClassWizard asks you to close any files, close ClassWizard, close the files, and then restart ClassWizard.

    ClassWizard displays a message box warning you that the old class could not be found.

  5. Click OK.

    The Repair Class Information dialog box appears.

    Supply the new information about the class in the Class Name, Header File, and Implementation File text boxes. If necessary, use the Browse button to supply the correct name of the header file or the implementation file.

  6. Click OK to update the .clw file.

See Also Keeping ClassWizard Updated When Code Changes, Deleting Classes, Rebuilding the ClassWizard (.clw) File


Rebuilding the ClassWizard (.clw) File

Home | Overview | How Do I | Tutorial

If you have made numerous changes to your code or have added a large number of existing user-interface classes to your current project, you may find it convenient to rebuild the associated ClassWizard (.clw) file from scratch rather than update it one class at a time. To do this, delete your project's .clw file and use ClassWizard to generate a new one. The newly-generated .clw file contains information about all the classes that have the special-format ClassWizard comments. For information on the ClassWizard special-format comments, see MFC Technical Note 6.

To rebuild the ClassWizard file

  1. Delete your project's .clw file.

  2. On the View menu, click ClassWizard.

    If ClassWizard appears, the project for which you deleted the .clw file is not the active project. From ClassWizard's Project drop-down list, select the project for which you want to rebuild the .clw file.

  3. If ClassWizard asks you to close any files, close ClassWizard, close the files, and then restart ClassWizard.

    A message box asks if you want to rebuild the ClassWizard file from your source files.

  4. Click Yes.

    The Select Source Files dialog box appears.

  5. Use the Add and Add All buttons to transfer all of the project's .h and .cpp files, and the .rc file from the File Name list to the Files In Project box. Click Remove to remove any files other than .h, .cpp, or .rc from the Files In Project box.

  6. Click OK.

    ClassWizard appears and generates a new .clw file.

  7. Click OK to close ClassWizard.

See Also Keeping ClassWizard Updated When Code Changes, Deleting Classes, Renaming or Moving Classes


ClassWizard: Tips and Troubleshooting

Home | Overview | How Do I | Tutorial

This article summarizes key tips and troubleshooting advice for using ClassWizard effectively. The following topics are covered:

  • Using ClassWizard tab dialogs

  • Adding functions with ClassWizard

  • Adding variables with ClassWizard

  • Adding code from ClassWizard

  • Opening your .rc file

Using ClassWizard Tab Dialogs

ClassWizard has a "tab dialog" user interface: the ClassWizard dialog box contains "tabs" that resemble the tabs on a group of file folders. Each tab's label shows what kind of functionality you can edit on that tab. To select a tab, click its label. Use the following tips:

  • Use the Message Maps tab to browse the messages that a class can handle or to create, edit, or delete the member functions mapped to the messages. Use the Edit Code button to jump to a message handler function's code in the Visual C++ source code editor.

  • Use the Member Variables tab to bind member variables to dialog, form view, or record view controls. You can also bind record view member variables both to record view controls and to the columns of a table in your data source.

  • Use the Automation tab to create and edit the Automation capabilities of your application. For example, you can create Automation properties and methods.

  • Use the ActiveX Events tab to specify actions that will cause your ActiveX control to fire events. For example, you can specify that a mouse click on your control fires a particular event that the control's container responds to with a handler. Note that this tab is for ActiveX control developers. If you are using an ActiveX control in your dialog box and want to handle events, use the Message Maps tab just as you would for handling messages.

  • Use the Class Info tab to browse and set general class options. You can set a class's message filter to determine what messages ClassWizard offers to map to handlers in your class. You can also view or set a "foreign object" associated with your dialog form view or record view class. For information about foreign objects, see the article ClassWizard: Foreign Objects.

Adding Functions with ClassWizard

ClassWizard lets you create handler functions and connect them to the menu items, toolbar buttons, and accelerators whose commands they respond to. Use the following tips:

  • To connect a dialog box or other user-interface object to a menu command or toolbar button with ClassWizard, you must first create the dialog box, menu entry, or toolbar button and its object ID using the appropriate Visual C++ resource editor.

  • You can bind more than one user-interface object to a single function. You can bind both a menu command and a toolbar button to a single function, for instance. In this case, selecting either object in your application causes the same action.

  • To add a function and edit its related code, you should make your selections in this order on the ClassWizard Message Maps tab:
    1. Select the Project that contains the class you want to edit.

    2. Select a Class name.

    3. Select an Object ID.

    4. Select a Message.

    You can then select an associated function to edit or delete, or click the Add Function button to add a member function to the class.

    By convention, the names of all message-handling functions begin with the prefix On.

  • Override virtual functions in much the same way, also on the Message Maps tab:
    1. Select a Class name.

    2. In the Object IDs box, select the class name again.

    3. In the Messages box, select a virtual function to override.

    4. Click Add Function.

Adding Variables with ClassWizard

ClassWizard lets you add member variables to some classes. For example, you can add member variables to a dialog class to represent the dialog box's controls. Use the following tips:

  • Edit Variables is available in the ClassWizard dialog box only for classes with a data map. This includes dialog, form view, and record view classes. Neither ClassWizard nor AppWizard make changes to your code outside the data map.

  • By convention, the names of all member variables begin with the prefix m_.

  • By using ClassWizard to map a dialog control to a dialog-class member variable with the Value property (the default), you can use dialog data exchange (DDX) and dialog data validation (DDV). This eliminates the need to move data between the control and the member variable yourself. It also allows you to specify validation rules for the data. For more information about DDX and DDV, see Dialog Data Exchange and Dialog Data Exchange and Validation.

  • You can also map a dialog control to a dialog-class member variable with the Control property. This creates a member variable of an appropriate class, such as CEdit. You can then call the member functions of the control object through this variable.

Adding Code from ClassWizard

After you've added a new member function in the ClassWizard dialog box, click Edit Code to add the implementation code for the function. A Visual C++ source code editor window opens with the file containing the class for the member function. A highlighted comment indicates where to add your code. Use the following tip:

  • You can select a function in ClassWizard's Message Maps tab and then click Edit Code to locate and examine code quickly.

Opening Your

RC File

Visual C++ lets you open resources in two ways. You can open individual resources (in compiled form) in the Visual C++ resource editors. Or you can open the .rc file to edit it directly as a text file. Use the following tip:

  • To open the .rc file as text, click the Open command on the File menu and change the Open As option to Text.


ClassWizard: Database Support

Home | Overview | How Do I | Tutorial

You can use ClassWizard to work with two main database classes for Open Database Connectivity (ODBC) or two main classes for Data Access Objects (DAO):

  • CRecordset (for ODBC) or CDaoRecordset (for DAO) Represents a set of records selected from a data source.

  • CRecordView (for ODBC) or CDaoRecordView (for DAO) Supplies a database form, based on a dialog resource template, whose controls map to the field data members of an associated recordset object.

Note If you are using the MFC ODBC class CRecordset, this article applies to recordsets in which bulk row fetching has not been implemented. For information about recordsets that implement bulk row fetching, see the article Recordset: Fetching Records in Bulk (ODBC).

DDX and Foreign Object Support

When you create a record view class, you associate it with a particular CRecordset-derived or CDaoRecordset-derived class and map the record view's controls to field data members of the recordset class.

This close association between a record view and a recordset takes advantage of another feature you can use in ClassWizard: "foreign objects." Dialog data exchange (DDX) lets you simplify data transfer between the controls in a dialog box or form view and the data members in a corresponding class. With foreign objects, you can exchange data between the controls and the data members of a separate object — in this case, between the controls of a record view and the data members of a recordset.

When you specify the CRecordset-derived class or CDaoRecordset-derived class to associate with a CRecordView-derived class or CDaoRecordView-derived class, you can name an existing recordset class or create a new one. ClassWizard adds a member variable to the record view class named, by default, m_pSet. The data type of this variable is the recordset class. The following figure shows the relationships between a record view on the screen, a record view object, and a recordset object. The recordset is the foreign object. ClassWizard creates the record view and recordset classes and maps record view controls to recordset data members via m_pSet.

DDX and Foreign Objects

Database Source Files

When you create a CRecordset/CDaoRecordset or CRecordView/CDaoRecordView class with ClassWizard, the wizard creates the classes in the files you specify in the Add Class dialog box. The default filenames are based on the class name you enter. You can modify the default names, place the recordset and record view in the same files, or consolidate all recordsets in one set of files.

Browsing and Editing Database Classes

You can also browse and edit existing classes with ClassWizard. When you edit an existing recordset class, ClassWizard provides a dialog box that you can use to update the table columns bound to the recordset if the table's schema has changed since you created the class. You can also, with a little extra work, use this mechanism to specify the columns of additional tables for a join of tables. For more information about joins in ODBC, see the article Recordset: Performing a Join (ODBC). Performing a join with DAO is similar.

The following articles explain the details of using ClassWizard's database support:

  • ClassWizard: Creating a Recordset Class

  • ClassWizard: Binding Recordset Fields to Table Columns

  • ClassWizard: Creating a Database Form

  • ClassWizard: Mapping Form Controls to Recordset Fields

  • ClassWizard: Foreign Objects

For more information about ODBC or DAO database support, see the article Databases: Overview.

See Also ClassWizard: Creating a Recordset Class, Visual C++ Wizards that Help You Begin Your Program


ClassWizard: Creating a Recordset Class

Home | Overview | How Do I | Tutorial

This article explains how to create a recordset class with ClassWizard.

You'll need a new CRecordset-derived class (for ODBC) or CDaoRecordset-derived class (for DAO) for each table, join of tables, or predefined query you work with in your program. Each recordset class specifies its own set of columns and may also specify parameters. For information about the structure of your recordset class and its uses, see the article Recordset: Architecture (ODBC) or DAO Recordset: Architecture.

For information about mapping recordset field data members to columns in the table, see the article ClassWizard: Binding Recordset Fields to Table Columns.

For information about using a CRecordset (ODBC) for a join of tables, see the article Recordset: Performing a Join (ODBC). (Performing a join with DAO is similar.)

For information about using a CRecordset for a predefined query, see the article Recordset: Declaring a Class for a Predefined Query (ODBC). For information about predefined ("saved") queries in DAO, see the article DAO Querydef.

Note When creating CRecordset-derived or CDaoRecordset-derived classes with ClassWizard, be careful when selecting multiple tables or queries. Selecting multiple tables or queries will result in the construction of a JOIN query without any restriction on how to perform the JOIN (called a cross product or a Cartesian product JOIN). You may wish to specify a filter using CRecordset::m_strFilter or CDaoRecordset::m_strFilter (resulting in MFC building an SQL WHERE clause) before the recordset is opened. This will constrain the number of records in the result set. This is especially necessary when using the ODBC Cursor Library, since the Cursor Library may create a large temporary file for result sets with many records.

The table below shows the major steps in creating a recordset class.

Recordset Class Creation Summary

To | Do this
Create the class | Use the Add Class dialog box in ClassWizard.
Select a data source and database table for the class | Select options in the Database Options dialog box. These include a data source, possibly a recordset type, and possibly some advanced options. Then specify details about the data source in the Select Database dialog box (for ODBC) or the Open dialog box (for DAO). Next, use the Select Database Tables dialog box to select tables from those available on the data source.
Remove any column mappings you don't want. By default, AppWizard and ClassWizard bind all columns in the table to recordset field data members | Select a column name on the Member Variables tab and choose Delete Variable.
Optionally parameterize the underlying SQL statements | Manually add parameter data members, or, in DAO, base your recordset on a parameterized a querydef object.
Optionally use dialog data exchange (DDX) to map recordset data members to controls in a record view | See the article Record Views.

For more information about parameterizing your class, see the article Recordset: Parameterizing a Recordset (ODBC) or the article DAO Queries: Filtering and Parameterizing Queries. For information about using DDX between record view controls and recordset data members, see the article ClassWizard: Mapping Form Controls to Recordset Fields.

To create the recordset class

You can add a new class derived from class CRecordset or CDaoRecordset in ClassWizard's Add Class dialog box. This dialog box is available from any tab in ClassWizard. (All figures follow the procedure below.)

  1. On the View menu, click ClassWizard.

  2. Click Add Class and select New from the drop-down list.

    The Add Class dialog box appears (see figure below).

  3. In the Name box, enter a name for the class; in the Filenames box, enter filenames for its .h and .cpp files.

  4. From the Base class drop-down list, select CRecordset as the base-class type of the new class. If you're using the MFC DAO classes, select CDaoRecordset.

  5. Click OK.

    The Database Options dialog box appears (see figure below).

  6. Choose ODBC or DAO. Then select a data source:
    • For ODBC, select from the drop-down list. Depending on what you choose, you might need to make a further selection in an Open dialog box. If the data source is on a server, you might be prompted to log in to the server.

    • For DAO, click the browse button beside the DAO edit control. Then, in the Open dialog box, navigate to the database file you want to use. (By default, the dialog box displays only Microsoft Jet databases, .mdb, but you can open any database that the Microsoft Jet database engine can read. For information, see the article Databases: Overview.
  7. Select the Recordset type (Snapshot, Dynaset, or Table) and Advanced features you want the class to have.

  8. Click OK.

  9. In the Select Database Tables dialog box (see figure below), select the name(s) of the table(s) you want.

    Click OK.

    On ClassWizard's Member Variables tab, notice that ClassWizard binds all of the table's columns to recordset field data members. For information about removing bindings you don't want, see the article ClassWizard: Binding Recordset Fields to Table Columns.

  10. When you finish, click OK to close ClassWizard. ClassWizard writes your class files in the specified directory and adds them to your project.

Specifying Information for a New Class

Selecting a Data Source in ClassWizard

Selecting a Database Table in ClassWizard

See Also ClassWizard: Database Support, ClassWizard: Binding Recordset Fields to Table Columns


ClassWizard: Binding Recordset Fields to Table Columns

Home | Overview | How Do I | Tutorial

Both AppWizard and ClassWizard bind all columns of your selected tables to the recordset. This article applies to both the MFC ODBC classes and the MFC DAO classes. The article explains how to:

  • Remove data members for any columns you don't want in the recordset.

    If you want only a subset of the columns bound by the wizards, use ClassWizard to remove the field data members for any columns you don't want.

  • Select table columns and map them to recordset field data members.

    If you subsequently remove any of the bindings the wizards made, you can later rebind them with ClassWizard.

  • Update columns in your recordset to reflect new columns in the table on the data source.

This and related articles use the terms "column" and "field" interchangeably when referring to recordset fields.

Removing Columns from Your Recordset

You might sometimes need to remove columns from a recordset. Both AppWizard and ClassWizard automatically bind all table columns to the recordset. If you want only a subset of the columns, use the following procedure.

To remove a column from a recordset

  1. In ClassWizard, click the Member Variables tab.

  2. Click a member variable name in the Members column of the Column Names box.

  3. Click Delete Variable.

    The member variable is removed from your recordset class. (The column in the data source to which the member variable was bound is not deleted.)

Warning Be careful not to remove any columns that are part of the table's primary key. In some tables, the primary key is a single column; in others, it's composed of two or more columns taken together. Removing these columns could damage your data on the data source.

Adding Columns to Your Recordset

Once you select a table, ClassWizard displays a list of all columns in the table. You can remove column bindings, and you can later rebind columns whose bindings have been removed. The following procedure explains how to bind an unbound column.

To add a column to the recordset

  1. Create the recordset class and associate it with one or more database tables.

    If you create the class with ClassWizard, follow the procedure To Create the Recordset Class in the article ClassWizard: Creating a Recordset Class.

    If you create the class with AppWizard, follow the information in the article Database Options in AppWizard.

  2. In ClassWizard, on the Member Variables tab, select the recordset class name in the Class Name box if it is not already selected.

  3. Select a column in the Column Names box.

  4. Click Add Variable to open the Add Member Variable dialog box.

  5. Type a name for the recordset data member that will represent the selected column.

  6. ClassWizard supplies a standard data member prefix, m_, for the name. Append the rest of the name to this prefix or type over it.

    The variable's property and data type are already specified in the dialog box. The property for these variables is always "Value." The data type is based on the data type of the column on the data source.

  7. Click OK to close the Add Member Variable dialog box.

  8. Click OK to close ClassWizard.

    ClassWizard writes your class files to the specified directory and adds them to your project.

Tip Rather than binding columns to data members one at a time, you can click the Bind All button to bind all columns. ClassWizard gives the data members default names based on the column names. Binding columns one at a time gives you more control over the columns bound and how they're named, but Bind All is quick and easy.

The following figure shows the Member Variables tab with a data member added for one of the available columns.

Adding a Data Member to the Recordset

Updating Your Recordset's Columns

Tables in a data source sometimes change—in particular, columns may be added to a table. To bring your recordset class up to date with respect to these changes, use the Update Columns button.

To update the columns in your recordset

  1. On ClassWizard's Member Variables tab, click your recordset class.

  2. Click Update Columns.

Any new columns are shown in the list but not yet bound to recordset field data members. To bind them, see the procedure To add a column to the recordset in Adding Columns to Your Recordset.

When you use Update Columns, columns you've previously bound to recordset data members are left alone; to unbind a column, delete its data member. Any columns in the table that aren't bound to the recordset disappear from the refreshed recordset.

See Also ClassWizard: Creating a Database Form, ClassWizard: Creating a Recordset Class


ClassWizard: Creating a Database Form

Home | Overview | How Do I | Tutorial

The Microsoft Foundation Class Library database classes supply class CRecordView (for ODBC) and class CDaoRecordView (for DAO) for implementing database forms with controls in which to display record fields. This article explains how to create a record view class with ClassWizard and associate it with a recordset class.

Important To use the MFC database classes, you must have specified at least minimum database support ("Only include header files") in AppWizard. If you didn't, open file Stdafx.h and add an #include directive for Afxdb.h (if you're using the MFC ODBC classes) or Afxdao.h (if you're using the MFC DAO classes).

The purpose of a record view class is to provide a form view whose controls are mapped directly to the field data members of a recordset object (and indirectly to the corresponding columns in a table on the data source). Setting up this mapping enables dialog data exchange (DDX) directly between the form's controls and the recordset's field data members. This article explains how to make the association.

Tip The easiest way to use a record view as your application's main view is to do so when you initially run AppWizard. See Database Options in AppWizard.

The following procedure begins the process.

To create a record view associated with a recordset

  1. Create the recordset class.

    See the article ClassWizard: Creating a Recordset Class.

  2. Create a dialog-template resource.

    See Using the Dialog Editor to Add Controls or Dialog Editor Topics for Visual C++ for more information.

    In the Styles and More Styles property pages of your dialog template, set the following properties, as you would for a CFormView object:

    • In the Style box, select Child (WS_CHILD on).

    • In the Border box, select None (WS_BORDER off).

    • Clear the Visible check box (WS_VISIBLE off).

    • Clear the Titlebar check box (WS_CAPTION off).

Tip As you place controls on your dialog template, you can help ClassWizard be smarter. See the tips in the article ClassWizard: Mapping Form Controls to Recordset Fields.

To continue from step 2, see the following procedure.

To create the record view class

  1. Run ClassWizard with the Visual C++ dialog editor open on your dialog-template resource.

  2. In the Adding a Class dialog box, click Create a new class (unless you are importing or using an existing class). For more information, see Adding a Class.

  3. In the New Class dialog box, specify CRecordView (for ODBC) or CDaoRecordView (for DAO) as the base class for the new class.

  4. Enter a name for the class and filenames for its .h and .cpp files and select any other options you need, such as Automation.

  5. Click Create.

  6. In the Select a Recordset dialog box, select the recordset class you created in step 1 of the procedure To create a record view associated with a recordset.

    -or-

    Click New to create a new recordset class. In this case, select a data source and table for the recordset as prompted. Close the Select a Recordset dialog box. On returning to the Member Variables tab, select your new recordset class.

  7. Bind columns to recordset field data members. See the article ClassWizard: Binding Recordset Fields to Table Columns.

    Note If you next click the Class Info tab, you'll see your recordset class listed in the Foreign Class box. For more information about "foreign" classes, see the article ClassWizard: Foreign Objects.

  8. Click OK to exit ClassWizard.

For information about binding your record view controls to the recordset, see the article ClassWizard: Mapping Form Controls to Recordset Fields.

See Also ClassWizard: Database Support, ClassWizard: Creating a Recordset Class, ClassWizard: Binding Recordset Fields to Table Columns


ClassWizard: Mapping Form Controls to Recordset Fields

Home | Overview | How Do I | Tutorial

A database form based on class CRecordView (for the MFC ODBC classes) or CDaoRecordView (for the MFC DAO classes) uses dialog data exchange (DDX) to exchange data between the form's controls and the field data members of the form's associated recordset object. This article explains how to use ClassWizard to set up the DDX connection between the controls and the recordset.

This connection is different from the normal use of DDX, which connects the controls in a dialog box directly to the data members of the associated dialog class. DDX for a record view object is indirect. The connection goes from form controls through the record view object to the field data members of the associated recordset object. For more information, see the articles Record Views and ClassWizard: Foreign Objects. The following table summarizes the mapping process.

Mapping Record View Controls to a Recordset

To | Do this
Specify the form control | Select the record view class on ClassWizard's Member Variables tab and select one of the form's control IDs
Specify the recordset data member to connect it to | Use the Add Variable dialog box to select a recordset data member indirectly

The following procedure assumes you have already followed the procedures in the article ClassWizard: Creating a Database Form. Specifically, you've created a CRecordset-derived or CDaoRecordset-derived class and added some field data members to it, created a dialog-template resource, created a CRecordView-derived or CDaoRecordView-derived class, and associated the record view class with the recordset class. Your record view class is associated with the dialog-template resource, to which you've added controls with the Visual C++ dialog editor.

To map the form controls to the recordset

  1. Click ClassWizard's Member Variables tab.

  2. In the Class Name box, select the name of your record view class.

  3. In the Control IDs box, select a control ID.

  4. Click the Add Variable button to name a variable associated with the control.

  5. In the Add Member Variable dialog box, choose a variable name by selecting a recordset data member in the Member Variable Name drop-down list box.

    Important Use the drop-down list box to select a data member name from the associated recordset (a foreign object). The names that appear are of the form m_pSet->m_recordsetVarName. You can type the name instead, but selecting from the drop-down list is faster and more accurate.

    All variables of the recordset class appear in the box, not just variables of the currently selected data type.

  6. Click OK to close the Add Member Variable dialog box.

  7. Repeat steps 3 through 6 for each control in the record view that you want to map to a recordset field data member.

  8. Click OK to close ClassWizard.

By selecting a name from the drop-down list, you specify a connection that passes through the record view object to a field data member of its associated recordset object.

Tip If you're running ClassWizard with the Visual C++ dialog editor open, the following shortcut is available. Choose a control on the form; then press CTRL and double-click the mouse. This opens ClassWizard's Add Member Variables dialog box, where you can bind a recordset field data member to the control. (If you use this shortcut before a class has been created for the dialog template, ClassWizard opens and displays its Add Class dialog box.)

If you follow a simple rule when placing controls on your record view form, ClassWizard is able to pre-select the most likely recordset member in the dialog box. The rule is to place the static text label for the control ahead of the corresponding control in the tab order.

Tip You can use CTRL+double-click for pushbuttons too. In these cases, ClassWizard creates a message handler function for the BN_CLICKED notification message in your record view class. You can edit its code to specify the button's action.

See Also ClassWizard: Foreign Objects


ClassWizard: Foreign Objects

Home | Overview | How Do I | Tutorial

ClassWizard extends dialog data exchange (DDX) by allowing you to map controls on a form or dialog box indirectly to a "foreign object" — a CRecordset or CDaoRecordset object. This article explains:

  • What foreign objects are.

  • How to use foreign objects.

Foreign Objects

The best way to understand foreign objects is to consider DDX for a dialog box or form view and then see how it is extended. This discussion considers a form view, based on class CFormView.

DDX maps the controls in a form view to data members of the CFormView-derived class associated with the dialog-template resource. Controls in a form view correspond one-to-one with form view class data members. Two entities are connected: the form view on the screen and the form view class. (Dialog boxes work this way too.)

DDX for foreign objects connects not two entities but three. The following figure shows this connection, with a record view on screen at one end, a CRecordView class in the middle, and a third object — the foreign object — at the other end: a CRecordset object. (These could be a CDaoRecordView and a CDaoRecordset.)

DDX for Foreign Objects

The record view class in the preceding figure contains a member variable, a pointer whose type matches the class of the foreign object. The DDX mapping is from three record view controls to members of the foreign object through the pointer, as illustrated by the following DoDataExchange function:

void CSectionForm::DoDataExchange(CDataExchange* pDX)
{
  CRecordView::DoDataExchange(pDX);
  //{{AFX_DATA_MAP(CSectionForm)
  DDX_FieldText(pDX, IDC_COURSE,
    m_pSet->m_strCourseID, m_pSet);
  DDX_FieldText(pDX, IDC_INSTRUCTOR,
    m_pSet->m_strInstructorID, m_pSet);
  DDX_FieldText(pDX, IDC_ROOMNO,
    m_pSet->m_strRoomNo, m_pSet);
  //}}AFX_DATA_MAP
}

Notice the indirect reference to recordset fields, through the m_pSet pointer to a CSections recordset object:

m_pSet->m_strCourseID

Also notice that m_pSet is repeated as the fourth argument in each DDX_FieldText call.

ClassWizard and Foreign Objects

You set the foreign class and object on ClassWizard's Class Info tab. The Foreign Class box names the class of the foreign object (CRecordset for ODBC or CDaoRecordset for DAO). The Foreign Object box names the pointer variable that points to an object of that class. (You can specify only one foreign object per class.)

If you select a class based on a dialog-template resource on ClassWizard's Member Variables tab, ClassWizard locates the appropriate pointer variable in the class and puts its type into the Foreign Class box. It also puts the variable name into the Foreign Object box. You can change these values if you wish.

If you create a CRecordView or CDaoRecordView class with AppWizard and then use ClassWizard to specify the DDX connections, ClassWizard automatically notes the presence in the view class of a pointer to a CRecordset-derived or CDaoRecordset-derived object. ClassWizard sets this as the value in the Foreign Class box. It puts the name of the pointer variable into the Foreign Object box.

See Also ClassWizard: Mapping Form Controls to Recordset Fields


ClassWizard: Automation Support

Home | Overview | How Do I | Tutorial

ClassWizard supports the following Automation features:

  • Add classes that support Automation. This makes your application an Automation server. These classes will be exposed to Automation clients such as Microsoft Visual Basic and Microsoft Excel.

  • Add methods and properties to your classes that support Automation.

  • Create a C++ class for another Automation object on your system, such as Microsoft Excel. This makes your application an Automation client.

    You must call AfxOleInit in InitInstance to initialize Automation for your application.

    For more information, see the article ClassWizard: Accessing Automation Servers.

An Automation class has a programming interface that other applications use to manipulate objects that your application implements. This is referred to as a "dispatch interface." For more information about dispatch interfaces, see Dispatch Interface and API Functions in the Win32 SDK.

ClassWizard's Add Class button now allows you to create classes supporting Automation. Click this button on the Automation tab to display a dialog box in which you can choose to create a new class or import an existing class. The New Class dialog box appears if you create a new class so you can specify the name of your class, the base class, the filenames in which your class is implemented, and the dialog display resource for the base class, if necessary. You can also choose whether your class supports Automation, and whether to add the new class to the Gallery.

To add an Automation class

  1. On the View menu, click ClassWizard.

  2. In ClassWizard, click the Add Class button. On the list that drops down, click New. The New Class dialog box appears.

  3. Type a name for the class.

  4. Select a base class. Typically, new automation classes are derived from CCmdTarget.

  5. If you do not like the filenames specified by ClassWizard, click Change. The Change Files dialog box appears.

    Type new names for the .h and .cpp files. Alternately, you can use the Browse buttons to select files. Then click OK to return to the New Class dialog box.

  6. Click the Automation option to expose this class to Automation clients. If you click Creatable by type ID, you can specify a Type ID for this automation object. The automation client will create an object of this class using the Type ID.

  7. When you have entered all the necessary information, click OK to create the necessary code and add it to your project.

To continue defining the dispatch interface for your Automation class, see the article ClassWizard: Adding Automation Properties and Methods.

A class that is OLE Creatable allows other applications to create a stand-alone object of the class, for example by using the Visual Basic function CreateObject, and to incorporate that automation object into their application. In general, you should make only your top-level classes, such as documents, creatable from other OLE applications. Classes that are parts of these top-level classes are usually not OLE Creatable and are instead accessed from a member function in the top-level class.

For example, consider a list document, which contains a list of items. It's a good idea to make the top-level document class OLE Creatable, because this allows other applications to create a list from nothing. You then add/enumerate the items in the list, but you cannot create them as stand-alone objects because they depend on their position inside the list. For this reason, only stand-alone objects should be OLE Creatable. Note that if you selected Creatable By Type ID in AppWizard your document class is OLE Creatable. In other words, it can be accessed by automation clients.

Note OLE insertable items are made possible by class COleTemplateServer. When you choose OLE support in AppWizard, a COleTemplateServer object manages your documents. Such documents can be created by Automation.

The following articles explain the details of using ClassWizard's OLE support:

  • ClassWizard: Adding Automation Properties and Methods

  • ClassWizard: Accessing Automation Servers


ClassWizard: Adding Automation Properties and Methods

Home | Overview | How Do I | Tutorial

This article explains how to use ClassWizard to add Automation (formerly OLE Automation) properties and methods to an Automation class. Topics include:

  • Adding a property to your automation class

  • Adding a method to your automation class

A class that supports Automation exposes a set of functions (known as methods) and properties — the dispatch interface — for use by other applications. ClassWizard offers a simple, quick way to implement this ability in your classes.

Adding a Property to Your Automation Class

To add a member variable property to your Automation class

Use member variable properties if you need to allocate storage for the values. The most common case for member variables is when there is no user interface to be updated when changes occur.

  1. In ClassWizard, click the Automation tab.

  2. Select a class name that supports Automation. (Your document class supports Automation if you checked the Automation check box in AppWizard when creating your project.) Notice that the Add Property and Add Method buttons are unavailable for classes that do not support Automation.

  3. Click Add Property and supply the following information:
    • External Name: Name that automation clients use to refer to this property.

    • Type: Any of the choices found in the list box.

    • Implementation: Click Member Variable.

    • Variable Name: Name of the C++ class data member.

    Tip You can also supply the name of a notification function that is called when the variable changes.

  4. Click OK to close ClassWizard.

To add a Get/Set method property to your Automation class

Use Get/Set methods properties if you are dealing with calculated properties. The most common use of Get/Set properties is to reflect changes in a user interface for calculated properties or items that are updated.

  1. In ClassWizard, click the Automation tab.

  2. Select a class name that supports Automation. You can also select the name of your document class if you checked the Automation check box in AppWizard when creating your project. Notice that the Add Property and Add Method buttons are unavailable for classes that do not support Automation.

  3. Click Add Property and supply the following information:
    • External Name: Name that automation clients use to refer to this property.

    • Type: Any of the choices found in the list box.

    • Implementation: Choose Get/Set Methods.

    • Get Function: The name of the member function used to get the property value.

    • Set Function: The name of the member function used to set the property value. This function can include special processing for when the property value is changed.
  4. Add any method parameters you need, using the grid control:
    • Double-click in the first empty row under the Name label to activate an edit control; then enter the parameter name.

    • Double-click the row under the Type label to activate a drop-down list; then select the parameter's type.

      Continue this procedure until you have entered all the parameters you need. To delete a parameter, delete its row by clicking once in the row and pressing the DELETE key or the BACKSPACE key.

  5. Click OK to create the necessary code.

Tip To create a read-only property, delete the name of the Set Function.

Adding a Method to Your Automation Class

  1. In ClassWizard, click the Automation tab.

  2. Select a class name that supports Automation. You can also select the name of your document class if you checked the Automation check box in AppWizard when creating your project. Notice that the Add Property and Add Method buttons are unavailable for classes that do not support Automation.

  3. Open the Add Method dialog box and supply the following information:
    • External Name: Name that automation clients use to refer to this method.

    • Internal Name: Name of the C++ member function to add to the class.

    • Return Type: Any choice found in the list box.
  4. Add any method parameters you need, using the grid control:
    • Double-click in the first empty row under the Name label to activate an edit control; then enter the parameter name.

    • Double-click the row under the Type label to activate a drop-down list; then select the parameter's type.

      Continue this procedure until you have entered all the parameters you need. To delete a parameter, delete its row by clicking once in the row and pressing the DELETE key or the BACKSPACE key.

  5. Click OK in the Add Method dialog box to create the member function.

See Also ClassWizard: Accessing Automation Servers, Automation Topics


ClassWizard: Accessing Automation Servers

Home | Overview | How Do I | Tutorial

Automation (formerly OLE Automation) allows other applications to expose objects and their interfaces to your application. You can make use of this feature by writing Automation clients in C++, as well as in Visual Basic and other interpreted languages that support Automation.

For information and a procedure, see the article Automation Clients: Using Type Libraries.


Adding a Class

Home | Overview | How Do I | Tutorial

Visual C++ provides several convenient ways to add error-free class declarations to your project.

ClassView, WizardBar, ClassWizard, and the New Class command (Insert menu) assist you with adding classes to an application. All the tools use the same interface (the New Class dialog), except that ClassWizard is limited to MFC-based classes. With ClassView, WizardBar, and the New Class command, you can create MFC (Microsoft Foundation Classes), ATL (Active Template Library), or generic (user-defined) classes. The type of class you add depends on your project type. For example, the default class for an MFC project is an MFC class. However, you can add ATL support to your MFC projects, just as you can add MFC support to your ATL projects.

You can also use the New Class dialog box to add a new class to existing class header and implementation files.

For ATL–based and MFC automation-enabled classes, you define the COM interfaces for the class when you create it. Defining interfaces is not part of creating a user-derived class.

What do you want to do?

  • Add an MFC class

  • Add an ATL class

  • Add a generic class

  • Add form-based class

  • Add ATL support to my MFC project

  • Create an ATL project that supports MFC

What do you want to know more about?

  • The New Class dialog box

  • Microsoft Foundation Class library (MFC)

  • Active Template Library

  • Working with COM interfaces

  • Editing COM interfaces

  • Classes offered by ClassWizard

The New Class Dialog Box

ClassView, WizardBar and ClassWizard all use the New Class dialog box to assist you in adding classes to your projects.

To open the New Class dialog box

  • Right-click on the project icon in ClassView, and click New Class on the shortcut menu.

    -or-

  • On the WizardBar Action menu, click New Class.

    -or-

  • On the Visual C++ Insert menu, click New Class.

    -or-

  • On the View menu, click ClassWizard. Click ClassWizard's Add Class button, and on the menu click New.

The New Class dialog box has four variants: one for MFC classes, one for ATL classes, one for Generic classes, and one for Form-based classes. The development environment detects the active project type, and modifies the New Class dialog box accordingly. The following table describes the class types that are available from the New Class dialog box for MFC and ATL projects.

Note When you access the New Class dialog box from ClassWizard, these options are not available. ClassWizard supports adding MFC classes only.

 | MFC .exe Project | MFC .exe Project with ATL Support | ATL COM Project | ATL COM Project with MFC Support
New MFC Class | x | x |  | x
New ATL Class |  | x | x | x
New Generic Class | x | x | x | x
New Form Class | x | x |  | x

See Also Adding a Member Function, Adding a Member Variable, Overriding a Virtual Function, Adding a Message Handler, Deleting a Member Function, Navigating the Class Structure


Adding ATL Support to Your MFC Project

If you've already created an MFC-based application, you can easily add support for the Active Template Library (ATL) by inserting any of the ATL objects into your project.

Note This support applies only to simple COM objects added to an MFC executable or DLL project. You can add other COM objects (including ActiveX controls) to MFC projects, but the objects might not operate as expected.

To add ATL support to your MFC project

  1. From ClassView, select the project to which you want to add ATL support, and click the right mouse button.

  2. From the popup menu, click New ATL Object … .

  3. When prompted, click Yes to add ATL support.

  4. From the ATL Object Wizard dialog, select the object you want to add.

    Note If you only want ATL support without adding any ATL objects, click Cancel in the ATL Object Wizard.


Details of ATL Support Added by the ATL Object Wizard

When ATL support is added (using ATL Object Wizard) to an existing MFC executable or DLL, several modifications are made to the existing MFC project. These modifications are as follows (in this example, the project is called MFCEXE):

  • Two new files are added: an .idl file and an .rgs file, used to register the server.

  • In the main application header and implementation files (Mfcexe.h and Mfcexe.cpp), a new class (derived from CComModule) is added with several methods that initialize and terminate the ATL support of the project. In addition to the new class, a new function (InitATL) is called from the InitInstance function of the application class to initialize ATL. Code is also added to the ExitInstance function for ATL termination. In the header file, support is added to track the attempt to initialize ATL. Finally, two new header files are included (Initguid.h and Mfcexe_i.c) in the implementation file, declaring and initializing the new GUIDs for the CComModule-derived class.

  • To properly register the server, an entry for the new .rgs file is added to the project's resource file.

  • In the Stdafx.h and Stdafx.cpp files, the CComModule-derived class (CMfcExeModule) is declared and defined and new files are included (Statreg.h and Atlimpl.h) for static registry of the ATL support.

Notes for DLL Projects

When you add ATL support to an MFC DLL project, you will see some differences. First, a global variable, _Module, of type CComModule is added. In addition, code is added to the DLLRegisterServer and DLLUnregisterServer functions for registering and unregistering the DLL.

Note The ATL Object Wizard does not add entries to the DEF file for an MFC DLL. You must add these yourself.

If your project is a DLL COM server, you must export four functions by hand. To accomplish this, add the following to the EXPORTS section of your project's .def file:

DllCanUnloadNow    @1 PRIVATE
DllGetClassObject    @2 PRIVATE
DllRegisterServer    @3 PRIVATE
DllUnregisterServer    @4 PRIVATE


Create an ATL Project that supports MFC

When you first create a project based on the Active Template Library (ATL), you can specify that support for the MFC library classes be added to the project.

To include MFC support in an ATL-based project

  1. Start a new ATL COM AppWizard project. (From the File menu, choose New and click the Projects tab, then select the ATL COM AppWizard project type.)

  2. In the ATL COM AppWizard Step 1 dialog box, select the Support MFC checkbox.

  20. This option links your project to the MFC libraries, so that you can access any of the classes and functions they contain. It does so by declaring the application as an MFC application object (class) which can then initialize and clean up the ATL module:
    class CATL_COMApp : public CWinApp
{
public:
    virtual BOOL InitInstance();
    virtual int ExitInstance();
};

CATL_COMApp theApp;

BOOL CATL_COMApp::InitInstance()
{
    _Module.Init(ObjectMap, m_hInstance, &LIBID_ATL_COMLib);
    return CWinApp::InitInstance();
}

int CATL_COMApp::ExitInstance()
{
    _Module.Term();
    return CWinApp::ExitInstance();
}

You can view the application object class and its InitInstance and ExitInstance functions in ClassView.

See Also Using the ATL COM AppWizard


Adding an MFC Class

Home | Overview | How Do I | Tutorial

To add classes derived from MFC (Microsoft Foundation Class Library) classes to your project, you can use any of the following tools: ClassView, WizardBar, ClassWizard, or the New Class command on the Insert menu. You simply specify the new class's name, select the base class from which it is to be derived, and select the ID of the dialog box with which it is to be associated (if any). WizardBar creates a header file and an implementation file for the new class.

Note You can add MFC classes to an ATL COM application if you initially created the application with MFC support.

To add an MFC class to your project

  1. Open the New Class dialog box as described in the New Class dialog box.

  2. In the Class type drop-down list, select MFC Class.

  3. In the Name box, specify the name of the new class.

    The name you specify is reflected in the read-only File name box, where the .cpp file is specified. By default, the header file and the implementation file have the same name as the class file.

    • To change the names of the header and implementation files for this class, click Change and type the names in the Change Files dialog box.

    • To add the new class to existing files, click Change, then click the Browse button and locate the files you wish to add it to.
  4. Choose a base class from which to derive the new class. There are two kinds of MFC classes:
    • Those, such as CButton, that do not require a resource ID.

      Classes such as CButton or CEdit that are derived from base classes other than CDaoRecordView, CDialog, CFormView, CPropertyPage, or CRecordView do not require a resource ID. Because these classes do not require a resource ID, the New Class dialog's Dialog ID drop-down list is not active.

    • Those, such as CDialog, that do require a resource ID.

      For classes that require a resource ID (classes derived from CDaoRecordView, CDialog, CFormView, CPropertyPage, or CRecordView), it is more efficient if you first use the dialog editor to create the resource and its ID, then use ClassWizard to create a class associated with that resource ID.

      However, if you create the class first, then the resource, you can later associate the class to the resource using the procedure described in Associate an Existing Class with a Resource.

      For information on using the resource editors, see Resource Editor Topics (Specific to Visual C++).

      For information about creating database classes (CRecordView, CRecordset) and OLE classes, see the article ClassWizard: Database Support.

  5. For dialog-based classes, select the resource with which the class is to be associated from the Dialog ID drop-down list.

  6. Select the type of Automation support: None, Automation, or Createable by type ID. (Note that the base class must support Automation in order for any Automation options to be available.)
    • Select None if you want the new class to have no Automation capability.

    • Select Automation if you want to expose the capabilities of the new class through Automation.

      If you select this option, the newly created class will be available as a programmable object by automation client applications, such as Microsoft Visual Basic™ and Microsoft Excel. This option is available only for some classes.

    • Select Createable by type ID if you want to allow other applications to create objects of this class using Automation.

      With this option, automation clients can directly create an Automation object. The type ID in the text box is used by the client application to specify the object to be created; it is system-wide and must be unique. This option is available only for some classes.

    Note Use ClassWizard's Automation tab to add Automation methods and properties to an existing class. These methods and properties define a dispatch interface that Automation clients can use.

  7. Click OK to create the new class and add it to the project.

    The new class immediately appears in ClassView, and you can view its header and implementation files in the FileView pane of the project workspace.

See Also Adding an ATL Class, Adding a Generic Class


Adding an ATL Class

Home | Overview | How Do I | Tutorial

To add an ATL (Active Template Library) class to your project, your project must have been created as an ATL COM application, or contain ATL support for MFC applications. You can use the ATL COM AppWizard to create an ATL COM application, or add an ATL object to your MFC application to implement MFC support for the Active Template Library.

You can define COM interfaces for your new ATL class when you first create it, or add them later by using the Implement Interface command from the ClassView popup menu.

To add an ATL class to your ATL COM project

  1. Open the New Class dialog as described in the New Class dialog box.

  2. In the Class type drop-down list, select ATL Class.

  3. In the Name box, specify the name of the new class.

    The name you specify is reflected in the read-only File name box, where the implementation (.cpp) file is specified. By default, the header file and the implementation file have the same name as the class (except for a leading capital 'C' in the name).

    • To change the names of the header and implementation files for this class, click the Change button and type the names into the Change Files dialog box.

    • To add the new class to existing files, click Change, then click the Browse button and locate the files you wish to add it to.
  4. Under Interface Type, specify whether you want the interfaces for this class to be Dual or Custom.

    Implementing a dual interface, derived from IDispatch, enables both COM clients and automation controllers to access your class functions. Custom interfaces are derived from IUnknown and have no restrictions on the data types you can use, such as data structures or unsigned arguments.

  5. Under Interfaces, specify the number of interfaces for the new class.

    The Names box displays the names of the interfaces.

  6. Click Edit to edit the default interface data.

    If you do so, the Edit Interface Information dialog box appears:

    • In the Object short name box, enter the control name;

    • In CoClass name, type the name of the CoClass class that contains a list of interfaces supported by the object;

    • In Type name, type an object description that will appear in the registry;

    • In Type ID (ProgID), type a name that containers can use instead of the CLSID of the object.

    The related fields display text based on what you type in the Object short name box.

  7. Click OK to save changes and return to the New Class dialog box.

  8. Select the Aggregatable checkbox if you want this class to enable objects that can directly expose another object's interface pointer (default setting).

  9. Click OK to save your entries and exit the New Class dialog box.

This creates the associated implementation and header files for the new class, which you can view from the ClassView pane of the Project workspace.

For more information on ATL projects and ATL COM classes, see the Active Template Library Home Page.

See Also Adding a New interface to an Existing Object or Control, Adding a Connection Point to an Object, Adding a method to an Interface or non-MFC Dispinterface, Adding an MFC Class, Adding a Generic Class


Adding a Generic Class

Home | Overview | How Do I | Tutorial

A generic class is a class that you define or that is derived from a class that you define. To add a generic class, you can use ClassView, WizardBar, or the New Class command (Insert menu).

To add a generic class to your project

  1. Open the New Class dialog as described in the New Class dialog box.

  2. From the Class type drop-down list, select Generic Class.

  3. In the Name box, specify the name of the new class.

    The name you specify is reflected in the read-only File name box, where the .cpp file is specified. By default, the header file and the implementation file have the same name as the class file.

    • To change the names of the header and implementation files for this class, choose the Change button and type the names into the Change Files dialog.

    • To add the new class to existing files, click Change, then click the Browse button and locate the files you wish to add it to.
  4. Under Base Classes, in the Derived From column, type the name of the base class from which to derive the new class. In the As column, click the access the new generic class is to have with regard to the base class: public, protected, or private.

See Also Adding an MFC Class, Adding an ATL Class


Adding a Member Function

Home | Overview | How Do I | Tutorial

Note ClassWizard does not have the capability of adding a generic member function.

You can add a member function to any class using ClassView or WizardBar. The tools add a function declaration to the header file, and add a stub function to the class's implementation file, which you can then edit.

To add a member function using ClassView

  1. Select the class to which you want to add a function.

  2. With the mouse pointer over the selected class, click the right mouse button to display the shortcut menu, and choose Add Member Function.

    The Add Member Function dialog box appears.

  3. In the Function Type text box, type the function's return type.

  4. In the Function Declaration text box, type the function declaration. The Function Type text box contains the return type for the function, so here you type only the function name, followed by a list of the names and types of formal parameters enclosed in parentheses.

  5. Select an access specifier for the function from the Access group of options.

  6. If you want a static function, click the Static check box. Or, if you want a virtual function, click the Virtual check box.

  7. Click OK.

    This procedure adds a declaration to the header file for the class, and a corresponding function body in the implementation file for the class.

To add a member function with WizardBar

  1. Using WizardBar's Class drop-down list, select a class, then select Add Member Function.

  2. The Add Member Function dialog box prompts you for the Function Type and the Function Declaration.

    Specify whether the new member function will be public (default), protected, or private.

  3. You must also specify whether or not the function will be static, and whether or not it will be virtual. You can do so either by selecting the static or virtual check box, or by entering the word static or virtual in the Function Declaration. The default is a non-static, non-virtual function. For example, the following settings:
    • Function Type: BOOL

    • Function Declaration: Foo

    • Access: Public

    • Virtual: Yes (Selected)

    produce the following function declaration:

    virtual BOOL CAboutDlg::Foo();

See Also Adding a Class, Adding a Member Variable, Overriding a Virtual Function, Adding a Message Handler, Deleting a Member Function, Navigating the Class Structure


Adding a Member Variable

Home | Overview | How Do I | Tutorial

You can add a member variable to a class using ClassView or ClassWizard.

  • If you want to add a generic C++ member variable, you must use ClassView.

  • If you want to add a member variable for data exchange and data validation, you must use ClassWizard. ClassWizard is specifically designed to take the relevant information and use it to insert elements in your source files at the appropriate locations. ClassView adds a plain variable declaration to the header file.

Note WizardBar does not have the capability of adding a member variable.

To add a member variable using ClassView

  1. In ClassView, select the class to which you want to add a variable.

  2. With the mouse pointer over the selected class, right-click to display the shortcut menu, and click Add Member Variable.

    The Add Member Variable dialog box appears.

  3. In the Variable Type text box, type the Member Variable data type.

  4. In the Variable Name text box, type the variable name.

  5. Select an access specifier for the variable from the Access group of options.

  6. Click OK.

This procedure adds a variable definition to the header file for the class.

To add a member variable using ClassWizard

  1. On the View menu, click ClassWizard. Click the Member Variables tab. Select the class to which you want to add a variable.

  2. Click Add Variable.

  3. The Add Member Variable dialog box appears.

    In the Member variable name text box, type the name of the variable.

    In the Category drop-down list, select the appropriate type of variable (for example, Control).

    In the Variable type drop-down list, select the appropriate class that defines the variable's data type.

  4. Click OK.

This procedure adds a variable definition to the header file for the class.

See Also Adding a Class, Adding a Member Function, Overriding a Virtual Function, Adding a Message Handler, Deleting a Member Function, Navigating the Class Structure


Overriding a Virtual Function

Home | Overview | How Do I | Tutorial

Note Virtual functions can not be added to an ATL COM object using ClassView, WizardBar, or ClassWizard.

You can use ClassView, WizardBar, or ClassWizard to override virtual functions defined in a base class.

To override a virtual function with ClassView or WizardBar

  1. From ClassView, right-click on a class and click Add Virtual Function on the shortcut menu.

    -or-

    Using WizardBar's Class drop-down list, select a class, then on the Action menu click Add Virtual Function.

  2. The New Virtual Override dialog box appears, prompting you with a list of virtual functions to add to the selected class. If you click Add Handler, the dialog adds a stub function to the class's implementation file, for example:
    // CChildFrame message handlers
void CChildFrame::ActivateFrame(int nCmdShow)
{
    // TODO: Add your specialized code here
    // or call the base class
    CMDIChildWnd::ActivateFrame(nCmdShow);
}

    If you want to edit the virtual function you are adding, click Add and Edit; this navigates to the file in which the new virtual function is implemented.

  3. If you want to edit an existing virtual function, select an item from Existing virtual function overrides, and click Edit Existing to navigate to the file in which the virtual function is implemented.

To override a virtual function with ClassWizard

  1. On the View menu, click ClassWizard.

    ClassWizard appears.

  2. On the Message Maps tab, under Class name, select the name of the class in which you want to override a virtual function.

  3. In the Object IDs box, select the class name.

    The Messages box displays a list of virtual functions you can override and a list of Windows messages. The virtuals come before the messages and appear in mixed case.

  4. In the Messages box, select the name of the virtual function you want to override.

  5. Click Add Function.

    The function is created and its name displayed in the Member Functions box. The names of virtual overrides are preceded by a gray glyph containing the letter "V" (handlers have a "W").

  6. Click Edit Code to jump to the virtual function definition.

See Also Adding a Class, Adding a Member Function, Adding a Member Variable, Adding a Message Handler, Deleting a Member Function, Navigating the Class Structure


Adding a Message Handler

Home | Overview | How Do I | Tutorial

You can use ClassView, WizardBar, or ClassWizard to add a message handler (a member function that handles Windows messages) to a class, and map Windows messages to the message handler. You can also quickly add a message handler for any dialog box control.

ClassWizard and WizardBar let you browse the messages associated with user-interface objects in your project. Both tools automatically update the message-dispatch table, or message map, and your class header file when you use them to define message-handling functions.

Note Adding a message handler to an ATL class is performed in the same way that you add a message handler to an MFC class, however some results may vary. For more information, see the topic Adding a Message Handler to an ATL Object

What do you want to know more about?

Mapping messages to functions

  • Default message handlers for controls

What do you want to do?

Add a message handler with ClassView or WizardBar

Add a message handler with ClassWizard

Quickly add a message handler for a control

Add a message handler for an ATL control

See Also Adding a Class, Adding a Member Function, Adding a Member Variable, Overriding a Virtual Function, Deleting a Member Function, Navigating the Class Structure


Mapping Messages to Functions

ClassView, WizardBar, or ClassWizard enable you to bind member functions of MFC classes (user-interface classes derived from the MFC library) to the messages generated by your application's resources. They use MFC message maps to create the binding.

Note ClassWizard is not for use when mapping messages to ATL objects. Instead use ClassView or the WizardBar only.

When you use ClassView, WizardBar, or ClassWizard to create a new class derived from one of the framework classes, it automatically places a complete and functional class in the header (.h) and implementation (.cpp) files you specify. ClassWizard keeps track of the class's message-handling and data-exchange members, so that you can update the class at a later time.

Note ClassWizard is only for use with MFC user-interface classes derived from CCmdTarget that handle messages or manage dialog box controls. To add a new class that does not handle messages, create the class directly in the text editor. (The exception to this rule is class CRecordset, for database support, which can be created with ClassWizard.)

To define a message handler with ClassView or WizardBar

  1. From ClassView, right-click on a class and click Add Windows Message Handler on the shortcut menu.

    -or-

    From WizardBar's Class drop-down list, select a class, then click Add Windows Message Handler on the Action menu.

    The New Windows Message and Event Handler dialog box appears.

  2. From the Class or Object to Handle list, select an item.

    The New Windows messages/events box displays a list of messages that you can add to the selected class or object. The Existing Windows message/event handlers box displays a list of messages already associated with the selected class or object. (Note that the Filter for messages available to class drop-down list allows you to select different sets of messages/events.)

Note If the selected class is a dialog class, form view, or record view, then the New Windows Messages and Event Handlers box includes window messages but not menu commands. To map menu IDs to messages in a class, you need to determine which class should handle the message (for example, CView or CMainFrame). Choose that class in the WizardBar Class drop-down list, select the menu ID from the Filter drop-down list, then from the Action menu select Add Windows Message Handler.

For information on handling custom messages, see MFC Technical Note 6.

  3. Select an item from the New Windows Messages and Event Handlers box, and click Add Handler to add the new handler function.

    WizardBar then adds a stub function to the class's implementation file. For example:

   // CChildFrame message handlers
   void CChildFrame::OnLButtonDblClk(UINT nFlags,
         CPoint point)
   {
      // TODO: Add your message handler code here
      // and/or call default

      CMDIChildWnd::OnLButtonDblClk(nFlags, point);
   }

Add and Edit performs the same function as Add Handler, except that after adding the message handler, Add and Edit navigates you to the file in which the message handler is implemented.

If you want to edit an existing message handler, or one you just added, select an item from Existing message/event handlers, and click Edit Existing to navigate to the file in which the message handler is implemented.

Quickly Adding Message Handlers for Dialog Box Controls

For dialog boxes in your project that are already associated with a class, you can take advantage of some shortcuts when creating message handlers. You can quickly create a handler for either the default control event, or for any applicable Windows message.

Note ClassWizard and the WizardBar can not be used for adding message handlers to ATL objects. Add a new message handler using the ClassView method.

To quickly add the default message handler for a control

  1. Open the dialog box resource that contains the control. (You can choose GoTo Dialog Editor from ClassView or WizardBar, or double-click the dialog resource from the ResourceView pane.)

  2. Double-click the control whose default message you want to handle.

  3. The Add Member Function dialog box appears, with the default handler selected (for example, BN_CLICKED for a push button), and a suggested event name (for example, OnOk).

    If the control already has a handler defined for it, double-clicking jumps you to the handler code in the Text editor.

  4. Click OK to have WizardBar generate the declaration and stub function code for the new message handler function.

Note You can disable this functionality by clearing the Double-click in dialog editor edits code checkbox on the Compatibility tab of the Options dialog (available from the Tools menu). In this case, double-clicking on a control opens the control's Properties page.

To quickly add a message handler for a control

  5. Open the dialog box resource that contains the control. (You can choose GoTo Dialog Editor from ClassView or WizardBar, or double-click the dialog resource from the ResourceView pane.)

  6. From the WizardBar Members drop-down list, select an unimplemented (non-bold) message.

    The Add Member Function dialog appears, with a proposed name for that message handler (for example, OnKeydownTab1 for the TCN_KEYDOWN message on a tabbed dialog with an object ID of IDC_TAB1).

    Note Selecting a bolded, or implemented message from the Messages list jumps you to that handler function in the Text editor.

  7. Click OK to accept the default name for the handler, or rename it and then click OK.

  8. WizardBar generates the function declaration and a stub function inside the dialog class, for example:
    afx_msg void OnKeydownTab1(NMHDR* pNMHDR, LRESULT* pResult);

    ……

    void CAboutDlg::OnSelchangeTab1(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here

*pResult = 0;
}

Default Control Events

Control name | Default event
Animate | NM_OUTOFMEMORY
Check Box | BN_CLICKED
Combo Box | CBN_EDITCHANGE
Custom | (Not applicable)
Date Time Picker | DTN_CLOSEUP
Edit Box | EN_CHANGE
Hot Key | NM_OUTOFMEMORY
IP Address | IPN_FIELDCHANGED
List | NM_CLICK
List Box | LBN_SELCHANGE
Month Calendar | MCN_GETDAYSTATE
Progress | NM_OUTOFMEMORY
Push Button | BN_CLICKED
Radio Button | BN_CLICKED
Rich Edit | NM_CLICK
Scrollbar | (Not applicable)
Slider | NM_OUTOFMEMORY
Spin | NM_OUTOFMEMORY
Tab | TCN_SELCHANGE
Tree | NM_CLICK

To define a message handler with ClassWizard

Two shortcuts are available for:

  • Defining message handlers for dialog buttons

  • Defining member variables for dialog controls
  1. On the View menu, click ClassWizard.

    ClassWizard appears and displays information about the currently selected class or the class you last edited with ClassWizard.

  2. Click the Message Maps tab.

  3. From the Class name drop-down list, select the class name of the user-interface component (such as a menu, accelerator, or dialog resource) you want to work with.

    ClassWizard displays information about the user-interface object that is currently selected.

  4. In the Object IDs box, select the name of the user-interface object for which you want to define a message handler.

  5. In the Messages box, select the message for which you want to define a handler. Click Add Function (or double-click the message name).

    Messages with handlers already defined are displayed in bold.

    Note The messages you see in the Messages box are those most appropriate to your class. If your class is not associated with the resource that contains the command that you want to handle, set the focus on the resource (for example, a dialog), open ClassWizard, and then use the Class name drop-down list to switch to the class from which you want the message handled.

    In addition, you can change the set of messages you handle by selecting the Class Info tab and selecting a new set of messages in the Message filter box. For information on handling custom messages, see MFC Technical Note 6.

    Tip Selecting a message displays a brief description of it at the bottom of the MFC ClassWizard dialog box.

    For messages that do not already have a predefined name for the handler function, the Add Member Function dialog box appears.

  6. If the Add Member Function dialog box appears, type a name for the member function and click OK.

    -or-

    From the Add Member Function dialog box, click OK to accept the default name.

    Either action returns you to the ClassWizard Message Maps tab.

    The message name is now displayed in bold to show that a message handler has been defined. The name of the new message hander appears in the Member functions box.

  7. At this point you have several options. You can:
    • Click Cancel to avoid updating your source code with the selected member functions.

    • Add more message handlers.

    • Click OK to update your source code with the selected member functions and close ClassWizard. You can return to ClassWizard any time during the development process.

    • Click Edit Code to jump to the definition of the function selected in the Member functions list just created by ClassWizard and begin defining the function's behavior.

    When you choose OK or Edit Code, ClassWizard updates your source code by:

    • Inserting a function declaration into the header file.

    • Inserting a complete, correct function definition with a skeletal implementation into the implementation file.

    • Updating the class's message map to include the new message-handling function.

For tips on adding message handlers to a class using ClassWizard, see Adding Functions with ClassWizard.

What do you want to know more about?

  • What Message Types Are Associated with Which User-Interface Objects?

  • Shortcut for Defining Message Handlers for Dialog Buttons

  • Shortcut for Defining Member Variables for Dialog Controls

  • Deleting a Message Handler

  • Editing a Message Handler

  • Defining a Message Handler for a Reflected Message

  • Declaring a Variable Based on Your New Control Class

  • Overriding a Virtual Function


What Message Types Are Associated with Which User-Interface Objects?

Home | Overview | How Do I | Tutorial

The following table shows the types of objects you work with in ClassWizard and the types of messages associated with them.

User-Interface Objects and Associated Messages

Object ID | Messages
Class name, representing the containing window (see the table in Classes Offered by ClassWizard) | Windows messages appropriate to a CWnd-derived class: a dialog box, window, child window, MDI child window, or topmost frame window.
Menu or accelerator identifier | COMMAND message (executes the program function). UPDATE_COMMAND_UI message (dynamically updates the menu item).
Control identifier | Control notification messages for the selected control type.


Shortcut for Defining Message Handlers for Dialog Buttons

Home | Overview | How Do I | Tutorial

Note This article applies only to dialog button controls within an MFC project. ATL projects should use the New Windows Messages and Event Handlers dialog box.

To define a message handler for a dialog button, you can use the following convenient shortcut to bypass some intermediate steps.

To define a message handler for a dialog box button

  1. In the dialog editor, select a button.

  2. While holding down the CTRL key, double-click the button.

    ClassWizard automatically creates a message handler in the class associated with the dialog box. The message handler is named according to the control ID of the dialog box button. Finally, the insertion point moves to the newly created function in your source code.

    -or-

  3. In the Dialog editor, double-click on the button.

  4. If a class is not already associated with the dialog, ClassWizard appears, along with an Adding a Class dialog box, which prompts you to provide a class for the new resource. You can either create a new class or select an existing class.

    If a class is already associated with the dialog box, the Add Member Function dialog box opens if no message handler for the control is implemented yet. If a message handler for the control is already implemented, you navigate directly to that handler's definition.


Shortcut for Defining Member Variables for Dialog Controls

Home | Overview | How Do I | Tutorial

To define a member variable for any dialog box control except buttons, you can use the following shortcut to bypass explicitly invoking ClassWizard from the dialog editor.

Note This article applies only to dialog controls within an MFC project. ATL projects should use the New Windows Messages and Event Handlers dialog box.

To define a member variable for a (non-button) dialog box control

  1. In the dialog editor, select a control.

  2. While holding down the CTRL key, double-click the dialog box control.

    The Add Member Variable dialog box appears.

  3. Type the appropriate information in the Add Member Variable dialog box. For more information, see Defining Member Variables for DDX.

  4. Click OK.

    ClassWizard returns you to the dialog editor.

Tip To jump from any dialog box control to its existing handler, double-click the control.


Deleting a Message Handler

Home | Overview | How Do I | Tutorial

Once you have defined a message handler, you can use ClassView, WizardBar, or ClassWizard to delete it. If you use ClassWizard, you must manually remove the function definition, as well as any references to the function, from the implementation file. ClassWizard deletes the declaration, but does not make changes to your implementation code — only to the message and data maps.

Note ClassWizard is unable to delete message handlers for ATL objects. Use ClassView or the WizardBar instead.

With ClassView and WizardBar, deleting a message-handling function is the same as deleting any other member function. ClassView and WizardBar delete the function declaration, removes any associated map entry from the MSG, MESSAGE or DISPATCH map, and comment out the function body, or definition, so that you can easily delete it if you wish.

Caution There is no UNDO facility for the deleted function declaration.

What do you want to do?

Use ClassWizard to delete a message handling function

Use WizardBar or ClassView to delete a member function

To use ClassWizard to delete a message-handling function

  1. In the ClassWizard dialog box, click the Message Maps tab.

  2. In the Class name box, select the class containing the message-handling function you want to delete.

  3. In the Member functions box, select the name of the member function to delete.

  4. Click Delete Function. This deletes the function entries from the message map for that class in both the header and implementation files.

  5. You will be reminded to edit the implementation file containing the member function. Using a text editor, comment out or delete the function header and function body.


Editing a Message Handler

Home | Overview | How Do I | Tutorial

Once you have defined a message handler with ClassWizard or WizardBar, you can use either tool to go to the member function's definition to add or modify code.

Note There is no support for editing message handlers of ATL objects using ClassWizard.

If you have the dialog editor open, double-click on a control for which a handler is already defined. This navigates you to the file in which the selected control's message handler is defined.

To jump to a member function definition with ClassWizard

  1. In the ClassWizard dialog box, select the Message Maps tab.

  2. In the Class Name box, select the class containing the message-handling function you want to edit.

  3. In the Member Functions box, select the function you want to edit.

  4. Choose Edit Code.

    -or-

    Double-click the function name.

    The insertion point moves to the function.

To jump to a member function definition with WizardBar

  1. Using WizardBar, select the class from the Class drop-down list, and the member function from the Member drop-down list.

  2. The WizardBar automatically navigates to the location in the implementation file in which the selected member function is defined.

  3. Subsequent clicks on the Action button navigate alternately between the function's definition and declaration.


Defining a Message Handler for a Reflected Message

Home | Overview | How Do I | Tutorial

Once you have created a new MFC control class, you can use either ClassWizard or WizardBar to define message handlers for it. Reflected message handlers allow your control class to handle its own messages before the message is received by the parent. You can use the MFC CWnd::SendMessage function to send messages from your control to a parent window.

With this functionality you could, for example, create a list box that will redraw itself rather than relying on the parent window to do so (owner drawn). For more information on reflected messages, see Handling Reflected Messages. To create an ActiveX control with the same functionality, you would have to create a project for the ActiveX control.

To define a message handler for a reflected message with ClassWizard

  1. in ClassWizard, click the Message Maps tab.

  2. From the Class name drop-down list, select the name of your control class.

  3. In the Object IDs box, select the name of your control class.

  4. In the Messages box, select the message for which you want to define a handler. Your class's reflected messages are marked with an equal sign (=).

    A message with a handler already defined is displayed in bold.

    Tip Selecting a message displays a brief description of it at the bottom of the MFC ClassWizard dialog box.

  5. Click Add Function (or double-click the message name).

    For messages that do not already have a predefined name for the handler function, the Add Member Function dialog box appears.

  6. Click OK to accept the proposed name.

    ClassWizard reappears. The message name is displayed in bold to show that a message handler is defined. The name of the new message hander appears in the Member functions box.

  7. At this point you have several options. You can:
    • Click Cancel to avoid updating your source code with the selected member functions.

    • Add more message handlers.

    • Click OK to automatically update your source code with selected member functions and close ClassWizard. You can return to ClassWizard any time during the development process.

    • Click Edit Code to jump to the empty function body just created by ClassWizard and begin defining the function's behavior.

    When you click OK or Edit Code, ClassWizard updates your source code as follows:

    • A function declaration is inserted into the header file.

    • A complete, correct function definition with a skeletal implementation is inserted into the implementation file.

    • The class's message map is updated to include the new message-handling function.

To define a message handler for a reflected message with WizardBar

  1. Using WizardBar, select the control class from the Class drop-down list, and click the Action button to navigate to the class's implementation (.cpp) file.

  2. From the Action menu, select Add Windows Message Handler.

    The New Windows Message Handler dialog appears.

  3. In Class or object to handle, the name of the control class should be selected.

  4. In the New windows messages box, select the message for which you want to define a handler. A class's reflected messages are marked with an equal sign (=).

    Click Add Handler or Add and Edit. WizardBar updates your source code as follows:

    • A function declaration is inserted into the header file.

    • A complete, correct function definition with a skeletal implementation is inserted into the implementation file.

    • The class's message map is updated to include the new message-handling function.

    WizardBar then moves the text-editor's insertion point to the body of the function.


Declaring a Variable Based on Your New Control Class

Home | Overview | How Do I | Tutorial

Once you have created an MFC control class, you can use ClassWizard to declare a variable based on it. To provide a context that ClassWizard can use to place the new variable, you must open the dialog editor and edit the dialog box in which you want to use your reusable control. Moreover, the dialog box must already have a class associated with it. For information on using the dialog editor, see Dialog Editor Topics for Visual C++. For information on using ClassWizard to add a class, see Adding a Class.

To declare a variable based on your reusable class

  1. While editing the dialog box, drag a control of the same type as the base class of your new control from the Controls toolbar onto the dialog box.

  2. Place the mouse pointer over the dropped control.

  3. While holding down the CTRL key, double-click the control.

    The Add Member Variable dialog box appears.

  4. In the Member Variables Name text box, type a name.

  5. In the Category drop-down list, click Control.

  6. From the Variable type drop-down list, select the name of your reusable control.

  7. Click OK.

    A message box reminds you to include (#include) your reusable control's header (.h) file into the project so that the compiler has access to its symbols. ClassWizard has no safe way of guaranteeing that your control class is in the scope of the dialog class.

  8. Click OK, and remember to include your control's .h file.

    ClassWizard generates dialog data exchange (DDX) code to attach your control class to the dialog control. Note that this procedure automatically subclasses the dialog control.


Deleting a Member Function

Home | Overview | How Do I | Tutorial

You can delete a member function by using ClassWizard, ClassView, or WizardBar. Deleting a function with ClassView or WizardBar removes the function declaration from the header (.h) file, removes any associated map entry from the MSG, MESSAGE or DISPATCH map, and comments out the function definition, if one exists. The function body remains selected so that you can easily delete it permanently if you wish.

If you delete a member function in the ClassWizard dialog box, the declaration is deleted from the class in the header file, and (if it is a message handler) any message-map entry is deleted from the implementation file. However, you must also manually remove the function definition, as well as any references to the function, from the implementation file. Browse through the class structure with ClassWizard to help you locate these references.

To delete a member function with ClassView

  1. In the ClassView pane, open the class that contains the function and select the function.

  2. Click the right mouse button, and choose Delete.

    A dialog box will prompt you to confirm that you want to delete the function.

  3. Click Yes to delete the specified function.

To delete a member function with WizardBar

  1. First ensure that the function is in a class that is part of the active project.

  2. Navigate to the function in the text editor, for example by using ClassView, or selecting it from the WizardBar Members combo list.

  3. With the function name displayed in the Members combo, open the WizardBar Action menu and click Delete.

    The Action menu appears when you choose the arrow next to the Action button, or when you click the right mouse button when focus is on a WizardBar combo control.

    A dialog box will prompt you to confirm that you want to delete the function.

  4. Click Yes to delete the specified function.

To delete a member function with ClassWizard

  1. In the ClassWizard dialog box, click the Message Maps tab.

  2. In the Class name box, select the class containing the member function you want to delete.

  3. In the Member functions box, select the name of the member function to delete.

  4. Click Delete Function. This deletes the function entries from the message map for that class in both the header and implementation files.

  5. You will be reminded to edit the implementation file containing the member function. Using a text editor, comment out or delete the function header and function body.

See Also Adding a Class, Adding a Member Function, Adding a Member Variable, Overriding a Virtual Function, Adding a Message Handler, Navigating the Class Structure


Navigating the Class Structure

Home | Overview | How Do I | Tutorial

You can go to a function definition using:

  • ClassView

  • WizardBar

  • ClassWizard: Select the Message Maps tab, select a class from the Class Name list, then a function from the Member Functions list. Click the Edit Code button to jump to the function definition.

You can go to a function declaration using:

  • ClassView

  • WizardBar

You can go to a class definition using:

  • ClassView

  • WizardBar

  • ClassWizard: Select the Message Maps tab, select a class from the Class Name list, then select the class name from the Object IDs list. Click the Edit Code button to jump to the class definition.

See Also Adding a Class, Adding a Member Function, Adding a Member Variable, Overriding a Virtual Function, Adding a Message Handler, Deleting a Member Function


Debugging Your Program

You have created your application and resolved the build errors. Now it's time to find and correct those logic errors that keep your application or stored procedures from running correctly. You can do this with the development environment’s integrated debugging functions.

This debugging section explains solutions to common problems in 32-bit programming. You’ll learn how to stop at procedure locations, inspect memory and register values, change variables, observe message traffic, and get a close look at how your code works -- or doesn’t!
What do you want to do?
Learn how to prepare a program for debugging.
Learn how to use the debugging tools.
Learn how to debug specific types of applications.
Read about special debugging techniques, problems, and solutions.
Debug an SQL stored procedure.

Interesting home pages
Visual C++ Editions Home Page Home for the entire Visual C++ product and gateway to all the documentation.
Compiling and Linking Information about building your program so you can test it.
Adding User Interface Features Look here to create user interface elements -- dialog boxes, toolbars, and much more.
Adding Program Functionality Tips for writing the code that implements what your program does.


Debugging Preparation

The debugging functions built into the development environment enable you to test your C++, MFC, and mixed language programs. You can set and manage breakpoints, view and alter variables, and control threads. During the debugging process, you can halt to examine the state of an executable program, a dynamic-link library (DLL), threads, or an ActiveX control at nearly any point during program execution.

Debugging is a two-step process. First, you correct compile-time errors that prevent you from building your project, such as incorrect syntax, misspelled keywords, or type mismatches. Then, you use the debugger to detect and correct logic errors and errors in sequencing, branching, and interaction among program components.

This section covers the following topics:

  • Debug Build Versus Release Build

  • Changing Project Settings for a Debug Build

  • What Are .PDB and .DBG Files?

  • Debugging Optimized Code

  • Enabling the Debugging Features

  • Enabling Just-in-Time Debugging


Debug Build Versus Release Build

When you create a new Visual C++ project, both a Win32 Debug and a Win32 Release version are automatically created with default options set for each.

Version | Default Values
Win32 Debug | Full symbolic debugging information in Microsoft format No optimization (optimization generally makes debugging more difficult)
Win32 Release | No symbolic debugging information Optimized for maximum speed

You can change the debug default options, for example, to output line numbers only, to generate a mapfile, or to redirect output.


Changing Project Settings for a Debug Build

When you create a Visual C++ project, a Win32 Release and a Win32 Debug version of the project files are automatically made. You can change the project settings in the C/C++ tab of the Project Settings dialog (from the Settings command on the Project menu).

Option | Result
Program Database (default) | Produces a program database (.pdb) containing type information and symbolic debugging information.
Line Numbers Only | Produces an .OBJ file or executable (.exe) file containing only global and external symbol and line-number information (no symbolic debugging information).
C7 Compatible | Produces an .obj file and an .exe file containing line numbers and full symbolic debugging information for use with the debugger.
None | Produces no debugging information.

For more information, see What Are .pdb and .dbg Files?.

To change the debug information generated during a build

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Choose the C/C++ tab.

  3. Choose an option from the Debug info dropdown list.

  4. Click OK to set the option and close the Project Settings dialog box.

To change the format of the debug information generated during a build

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Choose the Link tab.

  3. Choose Debug from the Category dropdown list.

  4. Select Microsoft Format (the default), COFF Format, or Both Formats.

  5. Click OK to accept the settings and close the Project Settings dialog box.

To generate a mapfile during a build

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Choose the Link tab.

  3. Choose Debug from the Category dropdown list.

  4. Select the Generate mapfile checkbox.

  5. Enter a name in the Mapfile name text box or accept the default.

  6. Click OK to accept the settings option and close the Project Settings dialog box.

To redirect debug input/output

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Select the Debug tab.

  3. In the Program Arguments text box, specify one or more I/O redirection commands from the following table. You can combine I/O redirection commands in any order.

  4. Click OK to accept the redirection and close the Project Settings dialog box.
Command | Action
<file | Reads stdin from file (see Note below)
>file | Sends stdout to file (see Note below)
>>file | Appends stdout to file (see Note below)
2>file | Sends stderr to file (see Note below)
2>>file | Appends stderr to file
2>&1 | Sends stderr (2) output to same location as stdout (1)
1>&2 | Sends stdout (1) output to same location as stderr (2)

Note You can use the >, <, >>, and 2> commands for applications that read or write to stderr and stdout. In most (if not all) cases, this is specific to console applications.


What are .pdb And .dbg Files?

This sections covers the following topics:

  • The .pdb Files

  • The .dbg Files


The .pdb Files

The .pdb (program database) file holds debugging and project state information. The .pdb file provides the information needed for incremental linking of debug program versions.

Although earlier, 16-bit versions of Visual C++ used .pdb files, the debugging information stored in them was appended to the end of the .exe or .DLL file by the linker. Now, with 32-bit .exe’s, both the linker and the integrated debugger allow .pdb files to be used directly during the debugging process, eliminating substantial amounts of work for the linker and bypassing the cumbersome CVPACK limit of 64K types.

By default, when you build projects generated by Visual C++, the compiler switch /Fd is used to rename the .pdb file to <project>.pdb. Therefore, you will have only one .pdb file for the entire project.

When you run makefiles that were not generated by Visual C++, and the /Fd is not used with /Zi, you will end up with two .pdb files:

  • VCx0.pdb (where x refers to the major version of the corresponding Visual C++). This file stores all debugging information for the individual .obj files and resides in the directory of the project makefile.

  • <project>.pdb This file stores all debugging information for the resulting .exe file and resides in the \WINDEBUG subdirectory.

Why two files? When the compiler is run, it doesn't know the name of the .exe file into which the .obj files will be linked, so the compiler can't insert the information into <project>.pdb. The two files store different information. Each time you compile an .obj file, the compiler merges the debugging information into VCx0.pdb. It only inserts information concerning types and does not insert symbol information such as function definitions. One benefit of this is that when every source file includes common header files such as <windows.h>, all the typedefs from these headers are only stored once, rather than in every .obj file.

When you run the linker, it creates <project>.pdb, which holds the debugging information for the project's .exe file. All debugging information, including function prototypes and everything else, is placed into <project>.PDB, not just the type information found in VCx0.pdb. The two kinds of .PDB files share the same extension because they are architecturally similar and they both allow incremental updates. Nevertheless, they actually store different information.

The Visual C++ debugger uses the <project>.pdb file created by the linker directly, and embeds the absolute path to the .pdb in the .exe or .dll file. If the debugger can't find the .pdb file at that location or if the path is invalid (for example, if the project was moved to another computer), the debugger looks for it in the current directory.


The .dbg Files

The .dbg (debug) files created with the 32-bit NT toolset are in the Portable Executable (PE) file format. They contain sections with COFF, FPO, and in some cases Codeview information. The Visual C++ integrated debugger can read .dbg files in this format, but it ignores the COFF symbol sections and looks only for Codeview information.

The Visual C++ integrated debugger can also use .dbg files as long as they are made from a binary containing Codeview format debugging output. These are useful for debugging when the source code is not available. Even without the source, .dbg files allow you to set breakpoints on functions, watch variables, and see the functions in the callstack. They are also required for OLE RPC debugging.

Tip When working with symbols from a .dbg file, you must use the fully decorated names. For example, to set a breakpoint on a call to the Windows sndPlaySound function, you would specify _sndPlaySoundA@8 as the location.

The earlier, 16-bit version of the Visual C++ .dbg file format was constrained by the 64K limit for a .com file. The symbolic information was therefore inserted into a separate .dbg file, which had only Codeview information in it. The .dbg files could also be generated by running CVPACK on an .exe file using the /strip option.

For 32-bit .EXEs, Visual C++ reads the format used in the Windows NT .dbg files (supplied for use with its system .dll files). These .dbg files are in the Portable Executable (PE) file format and contain sections with COFF, FPO, and in some cases Codeview symbolic information. The Visual C++ debugger reads .dbg files in this format only. Furthermore, it only uses the Codeview information, ignoring the other symbol sections.

It is possible to strip debug information from a PE file and store it in a .dbg file for use by debuggers. For this to work, the debugger needs to know whether to find the debug information in a separate file or not and whether the information has been stripped from the file or not. One method would be for the debugger to search through the executable file looking for debug information. However, to save the debugger from having to search the file, a file characteristic field (IMAGE_FILE_DEBUG_STRIPPED) indicates that the file has been stripped. Debuggers can look for this field in the PE file header to quickly determine if the debug information is present in the file.

To generate a .dbg file in this format, you can use REBASE.EXE, which is provided with the Win32 SDK. Please see the Win32 SDK documentation for more details.

During the Windows NT retail builds, debug symbols are stripped from the system binaries and drivers and stored in separate .dbg files. This is done because the Windows NT kernel debugger can use these .dbg files and provide debugging symbols even for optimized drivers. Remember, however, that the Visual C++ integrated debugger is not designed to debug protected mode kernel code.

The Windows NT symbol files can be found in a debug subdirectory of the \SUPPORT directory on the Windows NT retail compact disc. These files must be copied from the compact disc to your hard drive. For user mode debugging on the target debugger machine, .dbg symbols must be present in the Windows NT \<winnt>\SYMBOLS directory of the target system (<winnt> is the directory where Windows NT is installed). The Visual C++ setup program installs an "NT System Symbols Setup" icon in your program group. You can use it to automatically copy the .dbg files from your Windows NT compact disc to the correct directory structure on your hard drive.

For kernel debugging, place .dbg files into a symbols tree underneath the directory specified by the _NT_SYMBOL_PATH environment variable (for example, C:\DEBUG\SYMBOLS). Kernel debugging is possible with a minimal set of symbols consisting of symbols for all the drivers (*.sys) in the SYMBOLS\SYS directory, and symbols for NTOSKRNL.EXE and HAL.DLL in the SYMBOLS\EXE and SYMBOLS\DLL directories, respectively.

For more information, refer to the discussion regarding kernel debugging in the Windows NT DDK Programmer's Guide.


Debugging Optimized Code

During optimization, the compiler repositions and reorganizes instructions derived from your source code, resulting in more efficient execution of the program. Because the information in the optimized code has been rearranged, the debugger cannot always identify the source code that corresponds to a set of instructions. For this reason, it is advisable to debug your code before optimizing it whenever possible. You can enable optimization after you finish debugging.

Following are instructions for preventing optimization and suggestions for debugging optimized code, if necessary.

To prevent the compiler from optimizing code

  • When you create a new project, select the Win32 Debug target. Build and debug the Win32 Debug target until you are ready to build a Win32 Release target. The compiler does not optimize the Win32 Debug target.

    – or –

  • Use the /Od compiler option on the command line, and remove any other /O? compiler options.

    – or –

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Select the C/C++ tab.

  3. In the Optimizations drop-down list box, select Disable (Debug).

You can enable optimizations after you finish debugging.

Debugging optimized code

Some bugs affect optimized code but do not affect unoptimized code. If you must debug optimized code, use the following techniques:

  • Use the /Zi compiler option to get maximum symbolic information for your program.

  • Use the Disassembly and Registers windows. Set breakpoints at the appropriate locations using the Disassembly window.

To see why the Disassembly window is useful, consider the following example:

for (x=0; x<10; x++)

Suppose you set a breakpoint at this line. You might expect the breakpoint to be hit 10 times. But if this code is optimized, the breakpoint is hit only once, because the compiler recognizes that the first instruction associated with this line, which assigns the value of 0 to x, needs to execute only once. The compiler moves this instruction out of the loop. If you set a breakpoint on this source-code line, the debugger sets the breakpoint on the first instruction, which executes only once.

The instructions that compare and increment x remain inside the loop. To set a breakpoint on these instructions, use the Disassembly window. By viewing the object code the source-code line creates, you can set a breakpoint at the appropriate instruction. You can set a breakpoint at the location where the condition is checked or the variable is incremented. You can use the Step Into or Step Over commands in the Disassembly window to step by assembly instructions, which allows greater control than stepping by source-code line.


Enabling the Debugging Features

Debugging is enabled when your program is compiled with the symbol _DEBUG defined. This is typically done by passing the /D_DEBUG flag on the compiler command line. When you define the _DEBUG symbol, sections of code delimited by #ifdef _DEBUG / #endif are compiled.

You also must link with the debug versions of MFC libraries. Setting the Win32 Debug option in Visual C++ ensures linking with the debug libraries. The debug versions of the library have a “D” at the end of the library name. The static debug version of MFC is named NAFXCWD.LIB, and the static release version (nondebug) is named NAFXCW.LIB. The DLL debug version of MFC is named MFCvvD.LIB, and the DLL release version (nondebug) is named MFCvv.LIB (where vv is the version number).

To enable the debugging features

  • Choose the Win32 Debug target in the Select Active Configuration box on the Build toolbar.


Enabling Just-in-Time Debugging

With Just-in-time debugging, you can run a program outside Visual C++. When an application error occurs, it calls the Visual C++ debugger.

To enable Just-in-time debugging

  1. From the Tools menu, click Options.

  2. Select the Debug tab.

  3. Select the Just-in-time debugging check box.

  4. Click OK.

  5. From the Build menu, choose Build <project>.exe.

Note If you are running Windows NT, you must have administrator privileges to set the Just-in-time debugging option.


Debugging Specific Types of Applications

This section covers the following topics:

  • Debugging an ActiveX Control

  • Debugging COM Clients and Servers Using RPC Debugging

  • Debugging Assertions

  • Debugging Exceptions

  • Debugging Inline Assembly Code

  • Debugging DLLs

  • Debugging COM Applications with MFC

  • Debugging Remote Applications

  • Debugging Threads


Debugging an ActiveX Control

You can run, test, and debug an ActiveX control in the Visual C++ environment. Microsoft supplies a Test Container application so that you can test your control without having to write your own container.


Test Container

Home | Overview | How Do I | Tutorial | Sample

The Test Container application, shipped with Visual C++, is an ActiveX control container for testing and debugging ActiveX controls. Test Container allows the control developer to test the control’s functionality by changing its properties, invoking its methods, and firing its events. Test Container can display logs of data-binding notifications and also provides facilities for testing an ActiveX control’s persistence functionality: you can save properties to a stream or to substorage, reload them, and examine the stored stream data. This section describes how to use the basic features of Test Container. For additional information, select the Help menu while running Test Container.

To test your ActiveX control

  1. On the Tools menu of Visual C++, click ActiveX Control Test Container.

  2. On the Edit menu of Test Container, click Insert New Control.

  3. In the Insert Control box, select the desired control and click OK. The control will appear in the control container.

Note If your control is not listed in the Insert Control dialog box, make sure you have registered it with the Register Controls command from the File menu of Test Container.

At this point you can test your control’s properties or events.

To test your ActiveX control with the debugger

  1. Build a debug version of the control with symbolic debugging information.

  2. From the Build menu, select Settings.

    The Project Settings dialog box appears.

  3. Select the Debug tab.

  4. In the Executable for Debug Session box, type TstCon32.exe—the filename for Test Container.

Choose OK.

After you complete this procedure, Test Container starts automatically when you begin debugging your control (by selecting Go from the Debug submenu of Build or pressing F5). If a message box appears stating that no debug information is available for the Test Container, ignore the message and choose OK. You can now step through your code, set breakpoints, and use other debugging features.

To test properties

  1. On the Control menu, click Invoke Methods.

  2. In the Method Name drop-down list, select the PropPut method for the property you want to test.

  3. Modify the Parameter Value or Parameter Type and click on the Set Value button.

  4. Click Invoke to apply the new value to the object.

    The property now contains the new value.

To test events

You can specify the destination of event information.

  1. On the Options menu, click Logging.

  2. Specify the destination of event information.

See Also ActiveX controls


Debugging COM Clients and Servers Using RPC Debugging

You can use RPC (remote procedure call) debugging to debug COM client/server applications. You must enable RPC debugging if you want to use it.

To enable RPC debugging

  1. From the Tools menu, choose Options.

  2. In the Options dialog box, choose the Debug tab.

  3. Select the Just-in-time debugging check box.

  4. Select the OLE RPC debugging check box.

    Note With Windows NT, you must have administrator privileges to select the OLE RPC debugging check box.

  5. Choose OK.

RPC debugging works with two types of remote procedure calls:

  • In-process

  • Out-of-process

When the client you are debugging steps into an in-process remote procedure call, the debugger steps into the server code. If the in-process server runs on a different thread, the debugger switches focus to the server thread.

When the client you are debugging steps into an out-of-process remote procedure call, RPC debugging launches (or activates) a second instance of the debugger to handle the COM server you are stepping into. Similarly, when you are debugging a server that returns to the client, RPC debugging launches or activates an instance of the debugger for the client.

In either case (in-process or out-of-process), the debugger opens the source code for the server, if the source code is available. If the source code is not available, the debugger presents the disassembled object code in the Disassembly window.

If you are debugging a server and choose the Step Out command, the debugger returns to the client side.

Consider the following example. Suppose you have a COM server with an interface like this:

interface ISimpleServer {

   HRESULT Method1(
      IN int   n
      );
};

The client looks like this:

   ISimpleServer*   server = NULL;

   //
   // server = CoCreateInstance (... SIMPLE_SERVER );

   hr = server->Method1 (100);

   if (FAILED (hr))
   .
   .
   .

And the server looks like this:

HRESULT
CSimpleServer::Method1(
   int   n
   )
{
    char buffer [256];

    sprintf (buffer, ""n is %d\n", n);
    OutputDebugString (buffer);
}

With RPC debugging enabled, you might set a breakpoint on this line from the client application:

   hr = server->Method1 (100);

When the debugger reaches the breakpoint, you can choose Step Into. This command causes the debugger to step into the first line of CSimpleServer::Method1:

    char buffer [256];

If you then choose Step Out, control returns to the client on the next line of code:

   if (FAILED (hr))


Debugging Assertions

An assertion statement specifies a condition at some particular point in your program. Visual C++ supports assertion statements based on the following constructs:

  • The C run-time library _ASSERT, _ASSERTE Macros. For more information, see Using Macros for Verification and Reporting.

  • The Microsoft Foundation Class (MFC) ASSERT macro

  • The ANSI C/C++ assert function

Programs that use the MFC library should use the MFC ASSERT macro. Programs that use the run-time library should use the runtime _ASSERT macro. Other programs should use the ANSI assert function.

Assertion statements compile only when _DEBUG is defined. When _DEBUG is not defined, the compiler treats assertions as null statements. Therefore, assertion statements have zero overhead in your final release program; you can use them liberally in your code without affecting the performance of your release version.

Note The expression argument to ASSERT is not evaluated in the release version of your program. If you want the expression to be evaluated in both debug and release environments, use the VERIFY macro instead of ASSERT. In release environments, VERIFY evaluates the expression argument but does not check the result.

Catching Errors with Assertion Statements

Assertion statements are useful for catching logic errors. If you set an assertion on a condition that must be true according to the logic of your program, the assertion has no effect unless a logic error occurs. For example, suppose you are writing a simulation of gas molecules in a container, and the variable numMols represents the total number of molecules. Obviously, this number cannot be less than zero, so you might include an MFC assertion statement like this:

ASSERT(numMols >= 0);

This statement does nothing if your program is operating correctly. If a logic error has caused numMols to be less than zero, however, the statement halts the execution of your program and displays the Assertion Failed dialog box. This dialog box has three buttons, with the functions described in the following table.

Click this button | To do this
Retry | Debug the assertion or get help on asserts.
Ignore | Ignore the assertion and continue running the program.
Abort | Halt execution of the program and end the debugging session.

When the debugger halts because of an MFC or C run-time library assertion, it navigates to the point in the source file where the assertion occurred, if the source is available. The Debug tab of the Output window displays the assertion message that appeared in the Assertion Failed dialog box. If you want to keep a copy of the message for future reference, you can copy it from the Output window to a text window using copy and paste or dragging it. The Output window may contain other error messages as well. Examine these carefully; some may provide clues to the cause of the assertion failure.

When you add assertions to your code, avoid writing assertions that have side effects. For example:

ASSERT(numMols++ > 0); -- Don’t do this!

This assertion statement changes the value of numMols. If you write assertion statements that have side effects like this, the debug and release versions of your code will produce different results, because the side effects occur only when _DEBUG is defined. Be careful using assertion statements on library or system calls, which may have side effects.

Checking Results with Assertion Statements

Use assertion statements when you need to check the result of an operation. Assertions are most valuable for testing operations whose results are not obvious from quick visual inspection. Consider, for example, the following code, which updates the variable iMols based on the contents of the linked list pointed to by mols:

while (mols->type <> “H2O”)
{
 iMols += mols->num;
 mols = mols->next;
}
ASSERT(iMols<=numMols);

The number of molecules counted by iMols must always be less than or equal to the total number of molecules, numMols. A visual inspection of this loop does not guarantee that this must be the case, so an assertion statement is used after the loop to test for that condition.

Testing Error Conditions with Assertion Statements

Another use of assertion statements is to test for error conditions. Assertion statements are not a substitute for error-handling code, however. The following example shows an assertion statement that can lead to problems in the final release code:

myErr = myGraphRoutine(a, b);
ASSERT(!myErr); -- Don’t do this!

This code relies on the assertion statement to handle the error condition. As a result, any error code returned by myGraphRoutine will be unhandled in the final release code.

You can use assertion statements to check for error conditions at a point in your code where any errors should have been handled by preceding code. In the following example, a graphic routine returns zero if it succeeds and an error code if an error (such as running out of memory) occurs. You can use an MFC assertion statement as follows:

myErr = myGraphRoutine(a, b);
...
/* Code to handle errors and
   reset myErr if successful */
...
ASSERT(!myErr);

If the error-handling code works properly, any error that occurs is handled, and myErr is restored to a value of zero, indicating no error, before the assertion statement is reached. The assertion succeeds, and control passes to the next statement. However, if myErr has another value, the assertion fails, the program halts, and the Assertion Failed dialog box appears.

Examining Assertion Failures

When an assertion fails, you must examine your program to determine the cause of the failure. If the assertion statement and the cause of the failure occur close to one another, debugging can be relatively straightforward. Sometimes, however, an assertion failure may provide little or no clue as to where the cause is located. For example, suppose your code contained the following assertion statement:

ASSERT(ialloc %50 == 0);

The program in this example allocates memory in blocks of 50 bytes. This assertion tests to see that memory is allocated in multiples of the proper size. If the assertion fails, you know that a memory leak exists in your program. Your next task, of course, is to find out where.

To isolate the location where the memory leak occurs, you might add copies of this assertion statement to other parts of your program where memory is allocated. Another alternative is to set a data breakpoint.

To find the locations where a condition fails

  1. From the Edit menu, choose Breakpoints.

    The Breakpoints dialog box appears.

  2. Choose the Data tab.

  3. In the Enter The Expression To Be Evaluated text box, type the negation of the expression that caused the asertion failure.

    In general, for ASSERT (anyExpression), you can specify a data breakpoint as !(anyExpression).

    For example, if your program failed on the assertion:

    ASSERT(ialloc %50 == 0);

    In the Breakpoints dialog box, you would type:

    !(ialloc %50 == 0)
  4. Run your program again.

    Execution halts when the condition specified in the data breakpoint becomes true. This is the point where the condition in the assertion statement becomes false.

Finding Assertion Failures with the Call Stack Window

Another tool that is often useful for finding the cause of an assertion failure is the Call Stack window. Using the Call Stack window, you can examine previous functions and look for problems that may have caused the failure.

To navigate from the Call Stack window to a function’s source or object code

  1. From the View menu, click Debug Windows and Call Stack.

    The Call Stack window opens.

  2. In the Call Stack window, double-click the function name.

    – or –

    Select the function name, and press ENTER.

On rare occasions, you might want to look at the assertion-handling code rather than the code that caused the assertion to fail. You can use the Call Stack window for that purpose as well.


Debugging Exceptions

The debugger writes exception messages to the Output window. You can choose whether or not the program should halt or continue processing.

For Stop If Not Handled, the debugger writes a message to the Output window when an exception occurs, but does not halt the program unless the exception handler fails to handle the exception. At that point it is too late to fix the problem or examine the source code to see where the exception occurred because the program is already past the point where the exception occurred and is executing in the exception handler.

For Stop Always, the debugger stops the program and notifies you immediately when an exception occurs, before any handler code is invoked. You can look at the source window to see where the exception occurred, use the Watch and Variables windows and QuickWatch to see variable contents, and attempt to fix the exception yourself by modifying the variable contents. When you continue the program after the exception, a dialog box asks if you want to pass the exception back to the program’s exception handlers. If you fixed the problem, click No. Otherwise, click Yes, and the exception handler is invoked. If the exception handler cannot fix the problem, the debugger halts the program and notifies you as if the exception were Stop If Not Handled.

To set how the debugger handles exceptions

  1. From the Debug menu, click Exceptions.

    The Exceptions dialog box opens.

  2. Choose Stop Always or Stop If Not Handled for each exception type that can occur in your program.

The Exceptions list box in the Exceptions dialog box contains a default list of system exceptions. The information is saved in the project.DSW file, which persists with the project. If an exception is not included in this list, the debugger treats it as a Stop If Not Handled exception.

To add a new exception to the Exceptions list box

  1. From the Debug menu, click Exceptions.

    The Exceptions dialog box appears.

  2. In the Number box, type the exception number for the user-defined exception.

  3. Optionally, type the name of the exception in the Name box.

  4. Optionally, under Action, select the Stop Always or Stop If Not Handled option.

  5. Click Add.

  6. Click OK.

To change an exception parameter

  1. From the Debug menu, click Exceptions.

    The Exceptions dialog box appears.

  2. In the Exceptions list box, select the exception.

  3. Change any parameter, such as the name or the action.

  4. Click Change.

  5. Click OK.

To remove an exception from the Exceptions list box

  1. From the Debug menu, click Exceptions.

    The Exceptions dialog box appears.

  2. In the Exceptions list box, select the exception.

  3. Click Remove.

    When you delete an exception from the Exceptions list box, its action reverts to Stop If Not Handled.

  4. Click OK.

To restore all default system exceptions to the Exceptions list box

  1. From the Debug menu, click Exceptions.

    The Exceptions dialog box appears.

  2. Click Reset.

    All default system exceptions are restored to the Exceptions list box without disturbing any of the user-defined exceptions that have been added.

  3. Click OK.


Debugging Inline Assembly Code

You can use the Disassembly window to view the assembly instructions. Use the Registers window to view register contents.

For more information, see Viewing Disassembly Code, Viewing and Modifying Variables or Registers, and the procedure “To set or clear a Register flag” in Viewing and Modifying Variables or Registers.


Debugging DLLs

This section covers the following topics:

  • Methods for Debugging DLLs

  • Why Don’t My DLL Breakpoints Work?


Methods for Debugging DLLs

If you have the source for both the DLL and the calling program, open the project for the calling executable file and debug the DLL from there. If you load a DLL dynamically, you must specify it in the Additional DLLs category of the Debug tab in the Project Settings dialog box.

If you have the source for the DLL only, open the project that builds the DLL. Use the Debug tab in the Project Settings dialog box to specify the executable file that calls the DLL.

You can also debug a DLL without a project. For example, maybe you just picked up a DLL and source code but you don’t have an associated project or workspace. You can use the Open command on the File menu to select the .DLL file you want to debug. The debug information should be in either the .DLL or the related .PDB file. After Visual C++ opens the file, on the Build menu click Start Debug and Go to begin debugging.

To debug a DLL using the project for the executable file

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Choose the Debug tab.

  3. In the Category drop-down list box, select General.

  4. In the Program Arguments text box, type any command-line arguments required by the executable file.

  5. In the Category drop-down list box, select Additional DLLs.

  6. In the Local Name column, type the names of DLLs to debug.

    If you are debugging remotely, the Remote Name column appears. In this column, type the complete path for the remote module to map to the local module name.

  7. In the Preload column, select the check box if you want to load the module before debugging begins.

  8. Click OK to store the information in your project.

  9. From the Build menu, click Start Debug and Go to start the debugger.

You can set breakpoints in the DLL or the calling program. You can open a source file for the DLL and set breakpoints in that file, even though it is not a part of the executable file’s project.

To debug a DLL using the project for the DLL

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Choose the Debug tab.

  3. In the Category drop-down list box, select General.

  4. In the Executable For Debug Session text box, type the name of the executable file that calls the DLL.

  5. In the Category list box, select Additional DLLs.

  6. In the Local Module Name column, type the name of the DLLs you want to debug.

  7. Click OK to store the information in your project.

  8. Set breakpoints as required in your DLL source files or on function symbols in the DLL.

  9. From the Build menu, click Start Debug and Go to start the debugger.

To debug a DLL created with an external project

  1. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  2. Choose the Debug tab.

  3. In the Category drop-down list box, select General.

  4. In the Executable For Debug Session text box, type the name of the DLL that your external makefile builds.

  5. Click OK to store the information in your project.

  6. Build a debug version of the DLL with symbolic debugging information, if you don’t already have one.

  7. Follow one of the two procedures immediately preceding this one to debug the DLL.


Why Don't My DLL Breakpoints Work?

Why Don’t My DLL Breakpoints Work?

Some reasons why your breakpoints don’t work as expected are listed here, along with solutions or work-arounds for each. If you follow the instructions in one topic and are still having breakpoint problems, look at some of the other topics. Often breakpoint problems result from a combination of conditions.

  1. You can't set a breakpoint in a source file when the corresponding symbolic information isn't loaded into memory by the debugger.

    You cannot set a breakpoint in any source file when the corresponding symbolic information will not be loaded into memory by the debugger. Symptoms include messages such as "the breakpoint cannot be set" or a simple, noninformational beep.

    When setting breakpoints before the code to be debugged has been started, the debugger uses a breakpoint list to keep track of how and where to set breakpoints. When you actually begin the debugging session, the debugger loads the symbolic information for all the code to be debugged and then walks through its breakpoint list, attempting to set the breakpoints.

    However, if one or more of the code modules have not been designated to the debugger, there will be no symbolic information for the debugger to use when walking through its breakpoint list. Situations where this is likely to occur include:

    • Attempts to set breakpoints in a DLL before the call to LoadLibrary.

    • Setting a breakpoint in an ActiveX server before the container has started the server.

    • Other similar cases.

    To prevent this behavior in Visual C++, specify all additional DLLs and COM servers in the Additional DLLs field in the Debug/Options dialog box to notify the debugger that you want it to load symbolic debug information for additional .DLL files. When this has been done, breakpoints set in code that has not yet been loaded into memory will be "virtual" breakpoints. When the code is actually loaded into memory by the loader, these become physical breakpoints. Make sure that these additional debugging processes are not already running when you start your debugging session. The debugging process and these additional processes must be sychronized at the same beginning point to work correctly, hitting all breakpoints.

  2. Breakpoints are missed when more than one copy of a DLL is on your hard disk.

    Having more than one copy of a DLL on your hard drive, especially if it is in your Windows directory, can cause debugger confusion. The debugger will load the symbolic information for the DLL specified to it at run time (with the Additional DLLs field in the Debug/Options dialog box), while Windows has actually loaded a different copy of the DLL itself into memory. Because there is no way to force the debugger to load a specific DLL, it is a good idea to keep only one version of a DLL at a time in your path, current directory, and Windows directory.

  3. You can’t set "Break When Expression Has Changed" breakpoints on a variable local to a DLL.

    Setting a "Break When Expression Has Changed" breakpoint on a variable local to a DLL function before the call to LoadLibrary causes the breakpoint to be virtual (there are no physical addresses for the DLL in memory yet). Virtual breakpoints involving expressions pose a special problem. The DLL must be specified to the debugger at startup (causing its symbolic information to be loaded). In addition, the DLL's executable code must also be loaded into memory before this kind of breakpoint can be set. This means that the calling application's code must be executed to the point after its call to LoadLibrary before the debugger will allow this type of breakpoint to be set.


Debugging COM Applications with MFC

This section covers the following topics:

  • Debugging COM Applications

  • Debugging COM Containers

  • Debugging COM Servers

  • Debugging COM Containers and Servers Simultaneously

  • Debugging an SDI Server


Debugging COM Applications

ActiveX applications perform a number of tasks outside of the programmer’s direct control. Communication between DLLs, usage counts on objects, and Clipboard operations are just a few of the areas where you may encounter unexpected behavior. Usually when this happens, your first step is to track down the source of the problem. The difficulty with ActiveX applications is that it isn’t always obvious how to debug a particular problem. This series of topics describes techniques you can use to track down problems, some of which are unique to ActiveX applications. It also introduces you to the special tools and testing aids available to help you write solid ActiveX applications.

Debugging ActiveX applications begins with the same general debugging techniques you use in other kinds of applications. For more information, see Debugging Your Program and Using MFC Debugging Support.

Tip When you’re debugging an ActiveX server and container, start up two instances of Visual C++, load the container into one, and the server into the other, set appropriate breakpoints in each, and debug. When the container makes a call into the server that hits a breakpoint, the container will wait until the server code returns (that is, until you finish debugging it). You can also trace into calls that go across process boundaries. For more information on tracing into these calls, see The Trace Macro.


Debugging COM Containers

This topic briefly discusses an issue unique to COM container applications. Debugging a container application is very similar to debugging a standard MFC program, except when you attempt to debug an event that generates a callback (such as dragging data over the container application). In this case, you must set a breakpoint in the callback function.

Note The Visual C++ debugger supports stepping across and into containers and servers. This includes the ability to step across Remote Procedure Calls (RPC). For more information, see Debugging ActiveX Applications.

See Also Debugging COM Servers


Debugging COM Servers

Debugging COM server applications poses a unique set of problems that are not always easy to solve. This topic details debugging tasks that might not behave the way you would expect when debugging a server application.

If you do not have debugging information for your container application, or do not need to see symbolic information for the container, starting to debug the server application is a three-step process:

  1. Start debugging the server as a normal application.

  2. Set breakpoints as desired.

  3. Start the container application.

For information on viewing symbolic information for both the container and the server, see Debugging COM Containers and Servers Simultaneously.

Note The Visual C++ debugger supports stepping across and into containers and servers. This includes the ability to step across Remote Procedure Calls (RPC). For more information, see Debugging COM Applications.

See Also Debugging COM Containers


Debugging COM Containers and Servers Simultaneously

To debug both a container and a server at the same time, start a separate session of Visual C++ for each. That is, run multiple instances of Visual C++, one for the container and one for the server. See the Tip in the topic Debugging ActiveX Applications.


Debugging an SDI Server

If you are debugging an SDI server application, you should set the Program Arguments line of the Debug Options dialog box to “/Embedding” or “/Automation” so the debugger can launch the server application as though it were launched from a container. Starting the container from Program Manager or File Manager will then cause the container to use the instance of the server started in the debugger.


COM Debugging Tools

This section covers the following topics:

  • Using Test Applications

  • Using Viewers and Spy Programs


Using Test Applications

Test applications allow you to test various types of ActiveX applications against existing ActiveX applications. Visual C++ and the SDK provide a number of samples to use for testing. These include:

Container and Server

CL32TEST and SR32TEST are applications you can use to test your ActiveX applications. Both CL32TEST and SR32TEST are full-featured ActiveX applications and allow testing particular ActiveX API calls. This can be helpful in reproducing a series of events, one call at a time.

Outline Series

This series of applications shows how to convert a non-ActiveX application to an ActiveX server and container.

Microsoft Foundation Class Samples

The MFC ActiveX samples OCLIENT, SUPERPAD, and HIERSVR, as well as the MFC Tutorials CONTAINER and SCRIBBLE (Step 7), are also available to test your applications against. Full source code for these samples is included. CONTAINER and SCRIBBLE are fully explained in Tutorials.

The CL32TEST and SR32TEST tools are not installed on your hard disk. You can find them in the BIN directory on the Visual C++ compact disc.


Using Viewers and Spy Programs

Viewers and spy programs allow you to examine objects and events on your computer and in memory.

OLE2Viewer

OLE2VW32 displays the ActiveX and OLE objects installed on your computer and the interfaces they support. It also allows you to edit the registry and look at type libraries.

IDataObject Viewer

DOBJVIEW displays the list of data formats offered by ActiveX and OLE data objects created by the Clipboard or drag-and-drop operations.

Running Object Table Viewer

IROTVIEW displays information about ActiveX and OLE objects currently existing in memory.

Docfile Viewer

DFVIEW displays the contents of a small compound file. The executable file for DFVIEW is not on the Visual C++ compact disc. However, the source files for the SDK OLE sample DFVIEW are on the Visual C++ compact disc. To use DFVIEW, you must get the source code for this sample and build it.


Debugging Remote Applications

You can debug programs running on remote Intel platforms. During remote debugging, the one computer (the debugger host) controls debugging using a small remote monitor program on the second computer (the remote target). The debugger host computer communicates with the remote target computer through a network connection.

This section covers the following topics:

  • Setting Up the Remote Debug Monitor

  • Connecting the Host and Target Machines

  • Starting Remote Debugging

  • How Can I Keep Focus When Stepping Through My Program?

  • How Can I Use Debugger Windows While Debugging a Foreground Program?

  • How Can I Speed Up Remote Debugging?

  • Error: Unable to Resolve an IP Address

  • Error: The VC++ Debug Monitor Is Not Correctly Installed

  • Error: The Specified Debug Password Is Incorrect

  • Error: Cannot Open File on Remote Machine


Setting Up the Remote Debug Monitor

The remote debug monitor is a small program on the remote target computer. It communicates with the debugger host and controls the execution of the program you are debugging.

To install the remote debug monitor

  • On a Windows 95 or NT computer, the remote debug monitor consists of the following files: MSVCMON.EXE, MSVCRT.DLL, TLN0T.DLL, DM.DLL, MSVCP6O.DLL, and MSDIS110.DLL. For Windows NT only, the remote debugger also requires PSAPI.DLL. Copy these files to the remote target computer, move MSVCRT.DLL to the System32 directory, and restart.


Connecting the Host and Target Machines

Once remote debugging is enabled, you must specify the type of connection between the debugger host and the remote target: local or network.

Configure the remote connection on the debugger host computer first.

To configure a remote connection on the debugger host computer

  1. From the Build menu, click Debugger Remote Connection.

    The Remote Connection dialog box appears.

  2. In the Platform drop-down list box, select the appropriate platform.

  3. In the Connection drop-down list box, select the Network (TCP/IP) connection type.

  4. Click Settings.

    The Win32 Network Settings dialog box appears.

  5. Specify the remote machine’s name or address in the Target machine name or address field and enter the Debug monitor password.

    The password must match the password set on the remote target computer.

  6. Click OK to close the Win32 Network Settings dialog.

  7. Click OK to close the Remote Connection dialog.

Now, configure the remote target computer.

To configure a remote connection on the remote computer

  1. Launch MSVCMON.EXE.

    The Visual C++ Debug Monitor dialog box appears.

  2. Click Settings.

    The Win32 Network Settings dialog box appears.

  3. Specify the debugger host machine name or address in the Target machine name or address field and enter the Debug monitor password.

    The password must match the password on the remote target computer.

  4. Click OK.

  5. Click Connect.

    The Connecting dialog box appears. This dialog box will be hidden while you are debugging.

  6. Click Disconnect to break the remote connection when you are done remote debugging.


Starting Remote Debugging

After you have configured the connection on both ends, you can begin remote debugging.

To begin remote debugging

  1. Set up a shared directory that both the debugging host machine and the remote target machine can view.

    The shared directory can be on either machine or a network drive. The easiest option is to share the directory on the host machine that contains the project’s executable file.

    Note If you can’t make a shared directory, copy the executable file and any needed DLLs to the remote target computer. With this method you need to be sure that the executable files and DLLs are recopied whenever changes are made.

  2. Load the project into the Visual C++ development environment.

  3. From the Project menu, click Settings.

    The Project Settings dialog box appears.

  4. Choose the Debug tab.

  5. In the Category list box, select General and set the following items:
    • Executable for Debug Session Enter the name and path of the executable file as the debugger host computer sees it.

    • Working Directory Leave blank.

    • Remote Executable Path Enter the name and path of the executable file as the remote target computer sees it.
  6. In the Category list box, select Additional DLLs.

    Enter the name and path of any DLLs as the debugger host computer sees them.

  7. Start the remote debugger on the remote target computer.

    Find the Visual C++ and select the Visual C++ Debug Monitor icon. Click Connect to start the connection.

  8. From the Build menu, click Debugger Remote Connection.

    Confirm the choices for Platform and Connection or modify them as needed.

  9. Begin debugging.


How Can I Speed Up Remote Debugging?

Full Problem Description: I’m using remote debugging, but performance seems to be slow. What can I do to improve this?

To improve the speed of remote debugging, close any unneeded debugger windows to minimize the amount of information that must be sent across the connection. Also, minimize the use of data breakpoints.


Error: Unable to Resolve an IP Address

Full Error Text: Unable to resolve an IP address for the remote machine “xxxxxxx”.

This means that the machine name “xxxxxxx” could not translate into an IP address. The machine name for the remote connection is entered using the Debugger Remote Connection of the Build menu. Click Settings and check to make sure that the Target machine name or address is valid. At each machine that allows remote debugging, you must specify the Target machine name or address.

Tip You can also specify the Target machine name or address by running MSVCMON.EXE.


Error: The VC++ Debug Monitor Is Not Correctly Installed

Full Error Text: The VC++ Debug Monitor is not correctly installed and running on machine “xxxxxxx”.

This means that as remote debugging was beginning, it found the remote machine “xxxxxxx” but that machine was not running the debug monitor. Start the debug monitor on the remote machine before beginning the debug process.


Error: The Specified Debug Password Is Incorrect

Full Error Text: The specified debug password is incorrect.

Both the debugger host and remote target machines must use the same Debug monitor password. The password for the remote target machine is entered on the local machine using the Debugger Remote Connection of the Build menu. Click Settings and check to make sure that the Debug monitor password is valid. At each machine that allows remote debugging, you must specify the same Debug monitor password.

Tip You can also specify the Debug monitor password by running MSVCMON.EXE.


Error: Cannot Open File On Remote Machine

Full Error Text: Cannot open file “G:\<filename>” on remote machine.

Verify the filename and check to be sure the filepath is correct on the remote target machine.


Debugging Threads

This section covers the following topics:

  • Advice on using the Threads dialog box

  • SAMPLE: C Run-Time Application


Using the Threads Dialog Box

When debugging a multithreaded program, you can select a single thread using the Threads dialog box.

To display the Threads dialog box

  • From the Debug menu, click Threads.

The Threads dialog box displays a list of all threads in the application. Using this list, you can set focus on, suspend, or resume execution of a thread.

To set focus on a thread

  1. In the Theads dialog box, select a thread from the Thread list.

  2. Click Set Focus.

To suspend a thread

  1. In the Theads dialog box, select a thread from the Thread list.

  2. Click Suspend.

To resume execution of a thread

  1. In the Theads dialog box, select a thread from the Thread list.

  2. Click Resume.

The Thread list in the Threads dialog box displays status information on each thread as follows:

The Thread ID column contains the DWORD that uniquely identifies each thread. When you set focus on a thread, an asterisk (*) appears next to its thread ID.

The Suspend column contains the suspension number of each thread. This number, which can vary from 0 through 127, is incremented each time you suspend the thread and decremented each time you resume the thread.

The Priority column contains the thread priority. A thread priority can be any of the following: Idle, Lowest, Below Normal, Normal, Above Normal, Highest, or Time Critical.

The Location column contains the function name or address associated with the thread. You can choose to see either the function name or the address.

To view the function name associated with each thread

  • In the Threads dialog box, select Name.

To view the address associated with each thread

  • In the Threads dialog box, select Address.

If Name is selected, the current function name appears if it is known by the debugger. If no function is known, the address appears. If Address is selected, the current address appears.

Note If you are displaying thread locations by Name instead of by Address, each thread is typically shown with the function name in which its EIP currently resides. However, if the EIP is in a location where there are no symbols (for example, in the NT kernel), then Visual C++ displays, in brackets, the name of the topmost function on the stack for which symbols exist.


Sample: C Run-Time Application

This simple program illustrates most of the basic debugging features of the C run-time library, and the kind of debug output that results.

Build this sample as a Win32 console application. Your command line should look like the following:

cl -D_DEBUG /MTd -Od -Zi -W3 sample.c -link -verbose:lib -debug:full

In this example, sample.c is the name of the sample application, and you should substitute the name of the sample file. In console applications such as the following examples, debugging is complicated by the fact that errors do not interrupt execution of the program, as they normally would when directed to a message window.

/******************************************************
 *  EXAMPLE  1                                        *
 *  This simple application illustrates the basic     *
 *  debugging features of the C runtime libraries,    *
 *  and the kind of debug output that these features  *
 *  generate.                                         *
******************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

// This routine places comments at the head of a
// section of debug output
void OutputHeading( const char * explanation )
{
   _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}

// The following macros set and clear, respectively,
// given bits of the C runtime library debug flag, as
// specified by a bitmask.
#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

void main( )
{
   char *p1, *p2;
   _CrtMemState s1, s2, s3;

   // Send all reports to STDOUT
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );

   // Allocate 2 memory blocks, store a string in each
   p1 = malloc( 34 );
   strcpy( p1, "This is the p1 string (34 bytes)." );

   p2 = malloc( 34 );
   strcpy( p2, "This is the p2 string (34 bytes)." );

   OutputHeading(
      "Use _ASSERTE to check that the two strings are identical" );
   _ASSERTE( strcmp( p1, p2 ) == 0 );

   OutputHeading(
      "Use a _RPT macro to report the string contents as a warning" );
   _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );

   OutputHeading(
      "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
   _CrtMemDumpAllObjectsSince( NULL );

   free( p2 );

   OutputHeading(
      "Having freed p2, dump allocation information about p1 only" );
   _CrtMemDumpAllObjectsSince( NULL );

   // Store memory checkpoint in s1 memory-state
   // structure
   _CrtMemCheckpoint( &s1 );

   // Allocate another block, pointed to by p2
   p2 = malloc( 38 );
   strcpy( p2, "This new p2 string occupies 38 bytes.");

   // Store a 2nd memory checkpoint in s2
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Dump the changes that occurred between two memory checkpoints" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   // Free p2 again, store new memory checkpoint in s2
   free( p2 );
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Now the memory state at the two checkpoints is the same" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   strcpy( p1, "This new p1 string is over 34 bytes" );
   OutputHeading( "Free p1 after overwriting the end of the allocation" );
   free( p1 );

   // Set debug-heap flag so freed blocks are kept on
   // the linked list, to catch any inadvertent use of
   // freed memory
   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );

   p1 = malloc( 10 );
   free( p1 );
   strcpy( p1, "Oops" );

   OutputHeading( "Perform a memory check after corrupting freed memory" );
   _CrtCheckMemory( );

   // Use explicit calls to _malloc_dbg to save file
   //name and line number information, and also to
   // allocate Client type blocks for tracking
   p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
   p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
   strcpy( p1, "p1 points to a Normal allocation block" );
   strcpy( p2, "p2 points to a Client allocation block" );

   // You must use _free_dbg to free a Client block
   OutputHeading(
      "Using free( ) to free a Client block causes an assertion failure" );
   free( p1 );
   free( p2 );

   p1 = malloc( 10 );
   OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
   _CrtDumpMemoryLeaks( );

   // Set the debug-heap flag so that memory leaks are
   //reported when the process terminates. Then, exit.
   OutputHeading( "Program exits without freeing a memory block" );
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

Output

Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0

Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'

Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
 Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.

Now the memory state at the two checkpoints is the same:
**************************************************************************

Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.

Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.

Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse

Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.


Debugging Techniques, Problems, and Solutions

This section covers the following topics:

  • Tools and Tips

  • Resolving Compiler and Linker Errors

  • Using the Debug Heap from C++

  • Using the Debug Version Versus the Base Version

  • Using Macros for Verification and Reporting

  • Solving Buffer Overwrites and Memory Leaks

  • Writing Your Own Debug Hook Functions

  • Using C Run-Time Library Debugging Support

  • Using MFC Debugging Support

  • Using Object Dumps

  • How Can I View the Call Stack After an MFC ASSERT?

  • How Can I Debug Access Violations When Running My Program Standalone?

  • How Can I Debug an Access Violation?

  • How Can I Find Out If My Pointers are Corrupting a Memory Address?

  • How Can I Find Out Where My Pointer Is Getting Changed?

  • If Halted in MFC, How Can I Get Back to the Function That Called MFC?

  • How Can I Find Out Who Is Passing a Wrong Parameter Value?

  • When Calling a Function Hundreds of Times, Which Call Failed?

  • How Can I Debug an Active Process?

  • Where Can I Look Up Win32 Error Codes?

  • Can I Debug an .EXE Without a Project or Workspace?

  • Can I Debug a .DLL Without a Project or Workspace?


Tools and Tips

In addition to the standard debugging functions, the debugging environment provides many additional interface and process control features. For more information on standard debugging functions, see Home Page: Debugger.

This section covers the following topics:

  • Shortcut Menus

  • DataTips Pop-up Information

  • Using Breakpoints: Additional Information

  • Viewing and Modifying Variables or Registers

  • Stepping Into Windows Functions

  • Viewing Memory Contents

  • Viewing Disassembly Code

  • Why Can’t I Step Into Constructors and Operators Using the Step Into Specific Function?


Shortcut Menus

Each debugger window has a shortcut menu, which contains frequently used commands for that window.

To display the shortcut menu for a window

  • Click the right mouse button inside the window.

For example, if you click the right mouse button in the Variables window, you see a shortcut menu with several formatting options.

If you click the right mouse button in a source/text window, you see a shortcut menu with several commands, including Insert/Remove Breakpoint.

If you click a variable Var within a source window while you are debugging, the shortcut menu includes the command QuickWatch Var, which displays the variable Var in the QuickWatch dialog box.


DataTips Pop-up Information

The easiest way to see the value of a variable or expression when the debugger is stopped at a breakpoint is to use DataTips pop-up information.

You can view a DataTips pop-up information box for any variable or expression that appears in a source window and is within the current scope. To see a pop-up box for a variable, place the mouse pointer over the variable. To see a pop-up box for an expression, select the expression.

DataTips pop-up information is not available for invalid expressions, such as a division by zero. If you select an expression such as 1/0, no pop-up information box appears.


Using Breakpoints: Additional Information

In addition to the standard breakpoint functions, the debugging environment provides many additional breakpoint control features. For more information on standard breakpoints, see Setting Breakpoints.

This section covers the following topics:

  • Setting Breakpoints at a Memory Location Within the Current Scope

  • Setting Breakpoints Outside the Current Scope

  • Setting Breakpoints When Values Change or Become True

  • Setting a Breakpoint on a Message Received by a Windows Function

  • How Can I Fix “Breakpoint Has Moved” Errors?

  • Why Do Breakpoints Fail When Multiple Source Files Have the Same Name?


Setting Breakpoints at a Memory Location Within the Current Scope

You can use the Breakpoints dialog box to stop program execution at a particular memory location or when a specified condition occurs.

Note You can also set breakpoints outside of the current scope. For more information, see Setting Breakpoints Outside the Current Scope.

To set a breakpoint at a memory address

  1. From the View menu, click Debug Windows and Disassembly. The Disassembly window opens.

  2. In the Disassembly window, move the insertion point to the line where you want the program to break.

  3. Click the Insert/Remove Breakpoint toolbar button.

    A red dot appears in the left margin, indicating that the breakpoint is set.

To set a conditional breakpoint

  1. From the Edit menu, click Breakpoints.

    The Breakpoints dialog box appears.

  2. Select the Location tab.

  3. In the Break At text box, type the location (source line number, memory address, or function name) where you want to set the breakpoint.

  4. Click Condition.

    The Breakpoint Condition dialog box appears.

  5. Fill in the Expression and Number Of Elements text boxes as you would for a data breakpoint.

  6. In the Breakpoint Condition dialog box, click OK to set the condition.

  7. In the Breakpoints dialog box, click OK to set the breakpoint.

To set a conditional breakpoint with a skip count

  1. From the Edit menu, click Breakpoints.

    The Breakpoints dialog box appears.

  2. In the Breakpoints dialog box, select the Location tab.

  3. In the Break At text box, type a location (source line number, memory address, or function name) where you want to set the breakpoint. .

  4. Click Condition.

    The Breakpoint Condition dialog box appears.

  5. Fill in the Expression and Number Of Elements text boxes as you would for a data breakpoint.

  6. Fill in the Enter The Numbers Of Times To Skip Before Stopping text box. If you want your program to break every Nth time the condition is met at the specified location, set the Enter The Numbers Of Times To Skip Before Stopping to N - 1. (The debugger skips the breakpoint the first N times.)

  7. In the Breakpoint Condition dialog box, click OK to set the condition.

  8. In the Breakpoints dialog box, click OK to set the breakpoint.

Note The interface does not allow you to set both Enter The Numbers Of Times To Skip Before Stopping and Number Of Elements for the same breakpoint.


Setting Breakpoints Outside the Current Scope

If you want to set a breakpoint on a location or variable that is not within the current scope, there are two ways to do it:

  • Use the Advanced Breakpoint dialog box.

  • Specify the breakpoint directly on the Location or Data tab of the Breakpoints dialog box, using advanced breakpoint syntax.

Both methods achieve the same result, but the Advanced Breakpoint dialog box handles many details for you and does not require you to learn any special syntax.

Using the Advanced Breakpoint Dialog Box

To break on a location outside the current scope

  1. From the Edit menu, click Breakpoints.

  2. Click the Location tab on the Breakpoints dialog box.

  3. Select the drop-down arrow next to the Break At text box.

  4. From the menu that appears, click Advanced.

    The Advanced Breakpoint dialog box appears.

  5. In the Location text box, type the location (source line number, memory address, or function name) where you want to set the breakpoint.

  6. Under Context, type any necessary information in the Function, Source File, and Executable File text boxes. (It is not necessary to fill in all fields — only the ones you need to qualify the context.

    For example, to set a breakpoint at a line number in another source file, specify only the source file. To set a breakpoint in a dynamic-link library (DLL), you must specify the function, source file, and DLL. The DLL filename goes in the Executable File text box.)

  7. Click OK to close the Advanced Breakpoint dialog box.

    The information that you specified appears in the Break At text box in the Breakpoints dialog box.

  8. In the Breakpoints dialog box, click OK to set the breakpoint.

Using Advanced Breakpoint Syntax

To use advanced breakpoints syntax, you must qualify a breakpoint location or variable with a special context operator, as follows:

  • {[function],[source],[exe] } location

  • {[function],[source],[exe] } variable_name

  • {[function],[source],[exe] } expression

The context operator is a pair of braces ({}) containing two commas, and some combination of function name, source filename, and executable filename. If you omit either function or exe, the two commas cannot be omitted. The following syntax, for example, is illegal:

{File.c, File.exe} .143 — Bad

If you omit both source and exe, however, you can omit the commas. The following syntax is legal:

{Fun} .143

The location can be any line number, function, or memory address at which you can set a breakpoint. For example,

  • {[function],[source],[exe] } .100 — A line number (this may not work with some languages)

  • {[function],[source],[exe] } @100 — A line number (this works for all languages)

  • {[function],[source],[exe] } Traverse — A function name

  • {[function],[source],[exe] } CMyWindow::OnCall — A function name

  • {[function],[source],[exe] } 00406030 — A memory address (decimal)

  • {[function],[source],[exe] } 0x1002A — A memory address (hexadecimal)

  • {function,[source],[exe] } Label — A statement label. The context must include function since Label is visible in the function’s scope.

If the source or exe filename includes a comma, an embedded space, or a brace, you must use quotation marks around the filename so that the context parser can properly recognize the string. Single quotation marks are considered to be part of a Windows NT/Windows 95 filename, so you must use double quotation marks. For example,

{,”a long, long, name.c”, } .143

Another form of advanced breakpoints syntax uses the exclamation point instead of the context operator:

source!.location

This form of advanced breakpoint syntax does not include a function name or .EXE specifier. If you use this syntax to specify a filename that contains an exclamation point, you must surround the filename with double quotes:

“File.!c”!.115

You can also set data breakpoints. For more information, see Setting Breakpoints When Values Change or Become True.


Setting Breakpoints When Values Change or Become True

You can set data breakpoints that halt execution when an expression changes value or evaluates to true. The debugger automatically knows whether “changes” or “true” makes sense for the variable or expression you have entered — you don’t need to set this yourself.

You can set a breakpoint on any valid C or C++ expression. Breakpoint expressions can also use memory addresses and register mnemonics. The debugger interprets all constants as decimal numbers unless they begin with '0' (octal) or '0x' (hexadecimal).

This section covers the following topics:

  • Setting a Breakpoint When a Variable Changes Value

  • Setting a Breakpoint When an Expression Changes Value

  • Setting a Breakpoint When an Expression Is True

  • Setting a Breakpoint On a Variable Outside the Current Scope

  • Setting a Breakpoint When the Initial Element of an Array Changes Value

  • Setting a Breakpoint When the Initial Element of an Array Has a Specific Value

  • Setting a Breakpoint When a Particular Element of an Array Changes Value

  • Setting a Breakpoint When Any Element of an Array Changes Value

  • Setting a Breakpoint When Any of the First n Elements of an Array Change Value

  • Setting a Breakpoint When the Location Value of a Pointer Changes

  • Setting a Breakpoint When the Value at a Location Pointed to Changes

  • Setting a Breakpoint When an Array Pointed to by a Pointer Changes

  • Setting a Breakpoint When the Value at a Specified Memory Address Changes

  • Setting a Breakpoint When a Register Changes

  • Setting a Breakpoint When a Register Expression is True

Setting a Breakpoint When a Variable Changes Value

To set a breakpoint when a variable changes value

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the name of the variable.

  4. Click OK to set the breakpoint.

Setting a Breakpoint When an Expression Changes Value

To set a breakpoint when an expression changes value

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type an expression such as x+y.

  4. Click OK to set the breakpoint.

Setting a Breakpoint When an Expression Is True

To set a breakpoint when an expression is true

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type an expression, such as x==3, that evaluates to true or false.

  4. Click OK to set the breakpoint.

Setting a Breakpoint on a Variable Outside the Current Scope

To break on a variable outside the current scope

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the variable name.

  4. Select the drop-down arrow to the right of the text box.

  5. From the menu that appears, click Advanced.

    The Advanced Breakpoint dialog box appears.

  6. In the Expression text box, type the function name and (if necessary) the filename of the variable.

  7. Click OK to close the Advanced Breakpoint dialog box.

    The information that you specified appears in the Expression text box in the Breakpoints dialog box.

  8. In the Breakpoints dialog box, click OK to set the breakpoint.

Note You can enter context information directly into the Expression field, using the advanced breakpoints syntax. For details, see Using Advanced Breakpoint Syntax.

Setting a Breakpoint When the Initial Element of an Array Changes Value

To break when the initial element of an array changes value

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the first element of the array (myArray[0], for example).

  4. In the Number Of Elements text box on the Data tab, type 1.

  5. Click OK to set the breakpoint on myArray [0].

Setting a Breakpoint When the Initial Element of an Array Has a Specific Value

To break when the initial element of an array has a specific value

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type an expression containing the initial element of the array (myArray[0]==1, for example).

  4. In the Number Of Elements text box, type 1.

  5. Click OK to set the breakpoint on myArray [0].

Setting a Breakpoint When a Particular Element of an Array Changes Value

To break when a particular element of an array changes value

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the element of the array (myArray[12], for example).

  4. In the Number Of Elements text box, type 1.

  5. Click OK to set the breakpoint on myArray [12].

Setting a Breakpoint When Any Element of an Array Changes Value

To break when any element of an array changes value

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the first element of the array (myArray[0]).

  4. In the Number Of Elements text box, type the number of elements in the array.

  5. Click OK to set the breakpoint on myArray.

Setting a Breakpoint When Any of the First n Elements of an Array Change Value

To break when any of the first n elements of an array change value

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the first element of the array (myArray[0], for example).

  4. In the Number Of Elements text box, type n (for example, 10).

  5. Click OK to set the breakpoint on myArray[0] through myArray[9].

Setting a Breakpoint When the Location Value of a Pointer Changes

To break when the location value of a pointer changes

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the pointer variable name (p, for example).

  4. Click OK to set the breakpoint.

Setting a Breakpoint When the Value at a Location Pointed to Changes

To break when the value at a location pointed to changes

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the dereferenced pointer variable name (*p or p->next, for example).

  4. Click OK to set the breakpoint.

Setting a Breakpoint When an Array Pointed to by a Pointer Changes

To break when an array pointed to by a pointer changes

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the dereferenced pointer variable name (*p, for example).

  4. In the Number Of Elements text box, type the length of the array in elements. For example, if the pointer is a pointer to double, and the array pointed to contains 100 values of type double, type 100.

  5. Click OK to set the breakpoint.

Setting a Breakpoint When the Value at a Specified Memory Address Changes

To break when the value at a specified memory address changes

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type the memory address for the byte.

    For a word or doubleword memory address, enclose the address in parentheses, and precede it with a cast operator. For example, WO(21406036) for the word at memory location 21406036. Use the cast operator BY for a byte (optional), WO for a word, or DW for a doubleword. (The debugger interprets all integer constants as decimal unless they begin with zero (0) for octal or zero and x (0x) for hexadecimal.)

  4. In the Number Of Elements text box, type the number of bytes, words, or doublewords to monitor. If you used the BY operator in the Expression field, specify the number of bytes. If you used WO, specify the number of words. If you used DW, specify the number of doublewords.

  5. Click OK to set the breakpoint.

Setting a Breakpoint When a Register Changes

To break when a register changes

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type a register mnemonic, such as CS.

  4. In the Number Of Elements text box, type the number of bytes to monitor.

  5. Click OK to set the breakpoint.

Setting a Breakpoint When a Register Expression Is True

To break when a register expression is true

  1. From the Edit menu, click Breakpoints.

  2. Click the Data tab of the Breakpoints dialog box.

  3. In the Expression text box, type an expression that contains a boolean comparison operator, such as CS==0.

  4. In the Number Of Elements text box, type the number of bytes to monitor.

  5. Click OK to set the breakpoint.

Note When you set a data breakpoint, the debugger places the variable or variables used into a special debug register, if possible. The number of debug registers is limited. (Intel 80386 and later CPUs provide four debug registers. Motorola 680X0 and PowerPC chips have no debug registers.) Furthermore, stacked-based variables (parameters) cannot be placed into debug registers. If a breakpoint variable cannot be placed into a debug register, the debugger must examine the variable’s memory location after every instruction to determine whether the contents have changed. These extra memory accesses reduce execution speed of the program with the debugger. In some cases, the program may appear to hang. Performance may be especially slow if you are debugging a remote application.


Setting a Breakpoint on a Message Received by a Windows Function

You can set message breakpoints to stop the debugger when a particular WndProc function message is received.

Note Message breakpoints work only on x86- or Pentium-based systems.

To set a breakpoint on a message

  1. From the Edit menu, click Breakpoints.

    The Breakpoints dialog box appears.

  2. Click the Messages tab.

  3. In the Break At WndProc text box, type the name of the Windows function.

    If you are setting a breakpoint during a debug session, the list contains the exported functions in your project.

  4. In the Set One Breakpoint For Each Message To Watch list box, select the message.

  5. To set another breakpoint, press ENTER, and then repeat steps 3 and 4.

    The Breakpoints list displays the currently active breakpoints.

  6. Click OK to set the breakpoints.

Note If you interrupt execution while Windows or other system code is running, the results can be unpredictable.


How Can I Fix "Breakpoint Has Moved" Errors?

How Can I Fix “Breakpoint Has Moved” Errors?

Full Problem Description: I set a breakpoint at a line in my source code, but I’m actively editing the code as I debug. When I rebuild the project, I get an error message telling me that the breakpoint has moved. How can I stop this from happening?

Breakpoints set on source-code lines stay on the same line number. If you edit the code, changing the number of lines, the breakpoint may no longer be on a line with a valid statement.

Breakpoints set at the beginning of the function remain with the function, regardless of what source-code line the function begins on. If possible, set the breakpoint at the beginning of the function by specifying the function name, instead of setting the breakpoint on a line number.

For more information, see Setting Breakpoints.


Why Do Breakpoints Fail When Multiple Source Files Have the Same Name?

If two or more source files in the project have the same name, breakpoint problems are likely to occur. This often happens in cases where the user-named module has the same name as one of the components of a library (Debug version) they are linking with.

To work around this problem, try using the Context selection on the Advanced Breakpoint dialog box. In most cases, you can use the full paths to the source file and corresponding executable module.

For more information, see Setting Breakpoints at a Memory Location Within the Current Scope.


Viewing and Modifying Variables or Registers

The Variables window provides quick access to variables that are important in the program’s current context. Using the Variables window, you can modify the value of selected variables while the program is being debugged.

The Registers window displays the contents of the CPU registers, flags, and floating-point stack. Using the Registers window, you can change the value of any register or flag while the program is being debugged, or add registers (such as @EAX) to the Watch window.

To view the value in a register

  • From the View menu, click Debug Windows and Registers. Register values that have recently changed appear in red.

To view the return value of a function in the Variables window

  1. Step over or out of the function.

  2. In the Variables window, click the Auto tab.

  3. The Name column displays the return value as Name returned, where Name is the name of the function. The Return Value icon (a clockwise arrow) appears to the left of the function name.

    The function return value appears in the Value column.

To turn off the display of return values in the Variables window

  1. From the Tools menu, click Options.

  2. In the Options dialog box, select the Debug tab.

  3. Under Variables Window, clear the Return Value check box.

  4. Click OK.

To change the value of a register

  1. From the View menu, click Debug Windows and Registers.

  2. In the Registers window, use the TAB key or the mouse to move the insertion point to the register value you want to change.

  3. Type the new value.

  4. Press ENTER.

Caution Changing register values (especially in the EIP and EBP registers) can affect program execution.

To set or clear a Register flag

  1. From the View menu, click Debug Windows and Registers.

  2. In the Registers window, use the TAB key or the mouse to move the insertion point to the left of the value you want to change.

  3. Type the new value.

  4. Press ENTER.

The register flags and their set values for Intel x86 processors are the following:

Register Window Flags

Flag | Set
Overflow | O = 1
Direction | D = 1
Interrupt | I = 1
Sign | S = 1
Zero | Z = 1
Auxiliary carry | A = 1
Parity | P = 1
Carry | C = 1


Stepping Into Windows Functions

When the debugger is stopped on a line of source code with a call to the SendMessage or DispatchMessage function, you can use the Step Into command to step into the WndProc called by the function. To avoid stepping into the WndProc, Use the Step Over command instead.

Although SendMessage or DispatchMessage are the most common applications of this feature, you can also step into the following WndProc functions:

  • SendMessageTimeout

  • SendMessageCallback

  • SendNotifyMessage

  • SendDlgItemMessage

  • CallWindowProc

Note Because function pointers and member functions are bound at run time, the binding can change before a function call occurs. As a result, it is not always possible to step into a function pointer or member function.


Viewing Memory Contents

You can use the Memory window to view large buffers, strings, and other data that do not display well in the Watch or Variables window.

By default, the Memory window displays numbers in decimal (base 10) format. You can control the Memory window display by using options on the Debug tab in the Options dialog box on the Tools menu. To view Unicode in the Memory window, set the Format option to Wide Char. To display data bytes with Unicode characters, select the Show Data Bytes check box also.

To view memory contents at a specified location using drag-and-drop functionality

  1. From the View menu, click Debug Windows and Registers.

    The Memory window appears.

  2. In any window, select a memory address or pointer variable containing a memory address.

  3. Drag the address or pointer to the address section of the Memory window, and drop it.

To view memory contents at a specified location by editing

  1. From the View menu, click Debug Windows and Memory.

    The Memory window appears.

  2. Select the Memory window.

  3. In the Address box, select the memory address.

  4. Type or paste the new memory address and press ENTER.

    The Memory window displays the contents of memory locations beginning at the address specified in the Address box.

To view memory contents at a specified location using Go To

  1. From the View menu, click Debug Windows and Memory.

    The Memory window appears.

  2. Select the Memory window.

  3. From the Edit menu, click Go To.

    The Go To dialog box appears.

  4. In the Go To What box, select Address.

  5. In the Enter Address/Expression box, type or paste an address.

  6. Click Go To.

To specify a live expression for the memory location

  1. From the View menu, click Debug Windows and Memory.

    The Memory window appears.

  2. From the Tools menu, click Options.

    The Options dialog box appears.

  3. Click the Debug tab.

  4. In the Memory window Address box, type an address expression.

    You can type *pPtr, for example, to display memory contents starting at the address pointed to by pPtr.

  5. Click the Re-evaluate Expression check box.

  6. Click OK.

You can view some items more easily using live expressions. On an Intel-compatible system, you can examine the top of the stack by typing ESP as a live expression. By specifying a pointer variable, you can use the Memory window to follow the pointer as it increments through an array.


Viewing Disassembly Code

The Disassembly window displays assembly code with source-code annotations and symbols. You can view assembly code at a specified location using both drag-and-drop and the Go To command.

For additional information on displaying and using the Disassembly window, see Disassembly Window.

To view disassembly code at a specified location using drag-and-drop functionality

  1. From the View menu, click Debug Windows and Disassembly.

    The Disassembly window opens.

  2. In any window, select a memory address or pointer variable containing a memory address.

  3. Drag the address or pointer to the Disassembly window, and drop it.

To view disassembly code at a specified location using the Go To command

  1. From the View menu, click Debug Windows and Disassembly.

    The Disassembly window opens.

  2. Select the Disassembly window.

  3. From the Edit menu, click Go To.

    The Go To dialog box appears.

  4. In the Go To What box, select Address.

  5. In the Enter Address Expression box, type or paste an address.

  6. Click Go To.


Why Can't I Step Into Constructors and Operators Using the Step Into Specific Function?

Why Can’t I Step Into Constructors and Operators Using the Step Into Specific Function?

You cannot Step Into constructors or operators using the Step Into Specific Function because the Step Into Specific Function command depends on getting the literal string from the current line. This is a design limitation. For example, the constructor is not called using the syntax CConstructFunction::CConstructFunction, so the literal string is not available.


Resolving Compiler and Linker Errors

The first step in debugging is to fix language syntax errors. The Output window displays errors that prevent a program from being built and provides the file name, line number, and error number. You can copy and print information from the Output window. If the status bar appears, it gives a summary of the current error.

If you don’t understand an error message, move the insertion point to the error number and press the F1key (in the default keyboard mapping) to display online information about it.

To move through the list of errors

  • In the Output window, double-click the error, or select the error and press ENTER.

    – or –

    Click the right mouse button in the Output window, and click Go To Error/Tag from the shortcut menu.

    – or –

    Press F4 (in the default keyboard mapping) to select the next error.

    – or –

    Press SHIFT+F4 (in the default keyboard mapping) to select the preceding error.

    As each error is selected in the Output window, the corresponding line containing the error is selected in the source window.

To move to a specific line in a source file

  1. From the Edit menu, click Go To.

    The Go To dialog box appears.

  2. In the Line Number box, type a line number.

  3. Click Go To.

    If you type a line number greater than the last line in your source file, the editor moves to the end of the file.


Using the Debug Heap from C++

The debug versions of the C run-time library contain debug versions of the C++ new and delete operators. Unless you intend to make special use of the _CLIENT_BLOCK allocation type, be sure to define _CRTDBG_MAP_ALLOC when you are using C++. If this symbol is defined, all instances of new in your code are mapped properly to the debug version of new so as to record source file and line number information. If you use the _CLIENT_BLOCK type, you must call the debug version of the new operator directly or create macros that replace the new operator in debug mode, as shown in the following example:

/* MyDbgNew.h
/* Defines global operator new to allocate from
/* client blocks
*/
#ifdef _DEBUG
   #define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
   #define DEBUG_CLIENTBLOCK
#endif // _DEBUG

/* MyApp.cpp
/*  Compile options needed: /Zi /D_DEBUG /MLd
/*            or use a
/*      Default Workspace for a Console Application to
/*      build a Debug version
*/

#include "crtdbg.h"
#include "mydbgnew.h"

#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

void main( )  {
  char *p1;
  p1 =  new char[40];
  _CrtMemDumpAllObjectsSince( NULL );
 }

The debug version of the delete operator works with all block types and requires no changes in your program.


Using the Debug Version Versus the Base Version

The run-time library now contains special debug versions of the heap allocation functions that use the same names as the base versions and add the _dbg ending. This topic describes the differences in behavior between the debug version and the base version in a debug build of an application. The information in this topic is presented using malloc and _malloc_dbg as the example, but is applicable to all of the heap allocation functions.

Applications that contain existing calls to malloc do not need to convert their calls to _malloc_dbg to obtain the debugging features. When _DEBUG is defined, all calls to malloc are resolved to _malloc_dbg. However, explicitly calling _malloc_dbg allows the application to perform additional debugging tasks: it can separately track _CLIENT_BLOCK type allocations, and it can include the source file and line number where the allocation request occurred in the bookkeeping information stored in the debug header.

Because the base versions of the allocation functions are implemented as wrappers, the source file name and line number of each heap allocation request are not available by explicitly calling the base version. Applications that do not want to convert their malloc calls to _malloc_dbg can obtain the source file information by defining _CRTDBG_MAP_ALLOC. Defining _CRTDBG_MAP_ALLOC causes the preprocessor to directly map all calls to malloc to _malloc_dbg, thereby providing the additional information. To track particular types of allocations separately in client blocks, _malloc_dbg must be called directly and the blockType parameter must be set to _CLIENT_BLOCK.

When _DEBUG is not defined, calls to malloc are not disturbed, calls to _malloc_dbg are resolved to malloc, the definition of _CRTDBG_MAP_ALLOC is ignored, and source file information pertaining to the allocation request is not provided. Because malloc does not have a block type parameter, requests for _CLIENT_BLOCK types are treated as standard allocations.


Using Macros for Verification and Reporting

A common way of keeping track of what is going on in an application during the debugging process is to use printf statements in code such as the following:

#ifdef _DEBUG
   if ( someVar > MAX_SOMEVAR )
      printf( "OVERFLOW! In NameOfThisFunc( ),
               someVar=%d, otherVar=%d.\n",
               someVar, otherVar );
#endif

The _ASSERT, _ASSERTE, _RPTn, and _RPTFn macros defined in the CRTDBG.H header file provide a variety of more concise and flexible ways to accomplish the same task. These macros automatically disappear in your release build when _DEBUG is not defined, so there is no need to enclose them in #ifdefs. For debug builds, they provide a range of reporting options that can be directed to one of several debugging destinations. The following table summarizes these options:

Macro | Reporting Option
_ASSERT | If an asserted expression evaluates to FALSE, the macro reports the file name and line number of the _ASSERT, under the _CRT_ASSERT report category.
_ASSERTE | Same as _ASSERT, except that it also reports a string representation of the expression that was asserted to be true but was evaluated to be false.
_RPTn (where n is 0, 1, 2, 3, or 4) | These five macros send a message string and from zero to four arguments to the report category of your choice. In the cases of macros _RPT1 through _RPT4, the message string serves as a printf-style formatting string for the arguments.
_RPTFn (where n is 0, 1, 2, 3, or 4) | Same as _RPTn , except that these macros also include in each report the file name and line number at which the macro was executed.

Asserts are used to check specific assumptions you make in your code. _ASSERTE is a little more convenient to use because it reports the asserted expression that turned out to be false. Often this tells you enough to identify the problem without going back to your source code. A disadvantage, however, is that every expression asserted using _ASSERTE must be included in the debug version of your application as a string constant. If you use so many asserts that these string expressions take up a significant amount of memory, you may prefer to use _ASSERT instead.

Examining the definitions of these macros in the CRTDBG.H header file can give you a detailed understanding of how they work. When _DEBUG is defined, for example, the _ASSERTE macro is defined essentially as follows:

#define _ASSERTE(expr) \
   do { \
      if (!(expr) && (1 == _CrtDbgReport( \
          _CRT_ASSERT, __FILE__, __LINE__, #expr))) \
         _CrtDbgBreak(); \
    } while (0)

If expr evaluates to TRUE, execution continues uninterrupted, but if expr evaluates to FALSE, _CrtDbgReport is called to report the assertion failure. If the destination is a message window in which you choose Retry, _CrtDbgReport returns 1 and _CrtDbgBreak calls the debugger.

A single call to _ASSERTE could be used to replace the printf code at the beginning of this topic:

_ASSERTE(someVar <= MAX_SOMEVAR);

If _CRT_ASSERT reports were being directed to message boxes (the default) or to the debugger, then program execution would be interrupted when someVar exceeded MAX_SOMEVAR.

Asserts can also be used as a simple debugging error-handling mechanism for any function that returns FALSE when it fails. For example, in the following code, the assertion will fail if corruption is detected in the heap:

_ASSERTE(_CrtCheckMemory());

The following memory-checking functions can be used in asserts of this kind to verify pointers, memory ranges, and specific memory blocks:

_CrtIsValidHeapPointer

Verifies that a given pointer points to memory in the local heap; “local” here refers to the particular heap created and managed by this instance of the C run-time library. A dynamic-link library (DLL) could have its own instance of the library, and therefore its own heap, independent of your application’s local heap. Note that this routine catches not only null or out-of-bounds addresses, but also pointers to static variables, stack variables, and any other nonlocal memory.

_CrtIsValidPointer

Verifies that a given memory range is valid for reading or writing.

_CrtIsMemoryBlock

Verifies that a specified block of memory is in the “local” heap and has a valid block type. This function can actually do more than check a block’s validity, however. If you pass it non-null values for the request number, file name and/or line number, it sets the value in the block’s header accordingly.

For more information on how these and other assertion-checking routines can be used during the debugging process, see Debugging Assertions.

The printf code at the start of this topic reported actual values of someVar and otherVar to stdout. If these values were useful in the debugging process, one of the _RPTn or _RPTFn macros could be used to report them. The _RPTF2 macro, for example, is defined essentially as follows in CRTDBG.H:

#define _RPTF2(rptno, msg, arg1, arg2) \
   do { \
      if (1 == _CrtDbgReport(rptno, __FILE__, \
              __LINE__, msg, arg1, arg2)) \
         _CrtDbgBreak(); \
   } while (0)

The following call to _RPTF2 would report the values of someVar and otherVar, together with the file name and line number, every time the function that contained the macro was executed:

_RPTF2(_CRT_WARN, "In NameOfThisFunc( ), someVar= %d,
       otherVar= %d\n", someVar, otherVar);

Of course, you may only be interested in knowing the values of someVar and otherVar under the circumstance that someVar has exceeded its maximum permitted value. By using an assert, as described above, you could halt program execution and then use the debugger to examine the values of these variables. Alternatively, you could use a variation of the original printf code, enclosing a conditional call to the _RPTF2 macro in #ifdefs:

#ifdef _DEBUG
   if (someVar > MAX_SOMEVAR)
      _RPTF2(_CRT_WARN,
"In NameOfThisFunc( ), someVar= %d, otherVar= %d\n",
             someVar, otherVar );
#endif

Of course, if you find that a particular application needs a kind of debug reporting that the macros supplied with the C run-time library do not provide, you can write a macro designed specifically to fit your own requirements. In one of your header files, for example, you could include code like the following to define a macro called ALERT_IF2:

#ifndef _DEBUG                /* For RELEASE builds */
#define  ALERT_IF2(expr, msg, arg1, arg2)  ((void)0)
#else                         /* For DEBUG builds   */
#define  ALERT_IF2(expr, msg, arg1, arg2) \
   do { \
      if ((expr) && \
          (1 == _CrtDbgReport(_CRT_ERROR, \
               __FILE__, __LINE__, msg, arg1, arg2))) \
         _CrtDbgBreak( ); \
   } while (0)
#endif

One call to ALERT_IF2 could perform all the functions of the printf code at the start of this topic:

ALERT_IF2(someVar > MAX_SOMEVAR, "OVERFLOW! In NameOfThisFunc( ), someVar=%d, otherVar=%d.\n", someVar, otherVar );

This approach can be particularly useful as your debugging requirements evolve, because a custom macro can easily be changed to report more or less information to different destinations, depending on what is more convenient.


Solving Buffer Overwrites and Memory Leaks

This section covers the following topics:

  • Memory Management and the Debug Heap

  • Types of Blocks on the Debug Heap

  • Using the Debug Heap

  • Heap State Reporting Functions

  • Tracking Heap Allocation Requests


Memory Management and the Debug Heap

Two of the most common and intractable problems that programmers encounter are overwriting the end of an allocated buffer and leaking memory (failing to free allocations after they are no longer needed). The debug heap provides powerful tools to solve memory allocation problems of this kind.

The debug versions of the heap functions call the standard or base versions used in release builds. When you request a memory block, the debug heap manager allocates from the base heap a slightly larger block of memory than requested and returns a pointer to your portion of that block. For example, suppose your application contains the call: malloc( 10 ). In a release build, malloc would call the base heap allocation routine requesting an allocation of 10 bytes. In a debug build, however, malloc would call _malloc_dbg, which would then call the base heap allocation routine requesting an allocation of 10 bytes plus approximately 36 bytes of additional memory. All the resulting memory blocks in the debug heap are connected in a single linked list, ordered according to when they were allocated:

The additional memory allocated by the debug heap routines is used for bookkeeping information, for pointers that link debug memory blocks together, and for small buffers on either side of your data to catch overwrites of the allocated region.

Currently, the block header structure used to store the debug heap’s bookkeeping information is declared as follows in the DBGINT.H header file:

typedef struct _CrtMemBlockHeader
{
// Pointer to the block allocated just before this one:
   struct _CrtMemBlockHeader *pBlockHeaderNext;
// Pointer to the block allocated just after this one:
   struct _CrtMemBlockHeader *pBlockHeaderPrev;
   char *szFileName;   // File name
   int nLine;          // Line number
   size_t nDataSize;   // Size of user block
   int nBlockUse;      // Type of block
   long lRequest;      // Allocation number
// Buffer just before (lower than) the user's memory:
   unsigned char gap[nNoMansLandSize];
} _CrtMemBlockHeader;

/* In an actual memory block in the debug heap,
 * this structure is followed by:
 *    unsigned char data[nDataSize];
 *    unsigned char anotherGap[nNoMansLandSize];
 */

The “NoMansLand” buffers on either side of the user data area of the block are currently 4 bytes in size, and are filled with a known byte value used by the debug heap routines to verify that the limits of the user’s memory block have not been overwritten. The debug heap also fills new memory blocks with a known value. If you elect to keep freed blocks in the heap’s linked list as explained below, these freed blocks are also filled with a known value. Currently, the actual byte values used are as follows:

NoMansLand (0xFD)

The “NoMansLand” buffers on either side of the memory used by an application are currently filled with 0xFD.

Freed blocks (0xDD)

The freed blocks kept unused in the debug heap’s linked list when the _CRTDBG_DELAY_FREE_MEM_DF flag is set are currently filled with 0xDD.

New objects (0xCD)

New objects are filled with 0xCD when they are allocated.


Types of Blocks on the Debug Heap

Every memory block in the debug heap is assigned to one of five allocation types. These types are tracked and reported differently for purposes of leak detection and state reporting. You can specify a block’s type by allocating it using a direct call to one of the debug heap allocation functions such as _malloc_dbg. The five types of memory blocks in the debug heap (set in the nBlockUse member of the _CrtMemBlockHeader structure) are as follows:

_NORMAL_BLOCK

A call to malloc or calloc creates a Normal block. If you intend to use Normal blocks only, and have no need for Client blocks, you may want to define _CRTDBG_MAP_ALLOC, which causes all heap allocation calls to be mapped to their debug equivalents in debug builds. This will allow file name and line number information about each allocation call to be stored in the corresponding block header.

_CRT_BLOCK

The memory blocks allocated internally by many run-time library functions are marked as Crt blocks so they can be handled separately. As a result, leak detection and other operations need not be affected by them. An allocation must never allocate, reallocate, or free any block of Crt type.

_CLIENT_BLOCK

An application can keep special track of a given group of allocations for debugging purposes by allocating them as this type, using explicit calls to the debug heap functions. MFC, for example, allocates all CObjects as Client blocks; other applications might keep different memory objects in Client blocks. Subtypes of Client blocks can also be specified for greater tracking granularity. To specify subtypes of Client blocks, shift the number left by 16 bits and OR it with _CLIENT_BLOCK. For example:

#define MYSUBTYPE 4
_free_dbg(pbData, _CLIENT_BLOCK|(MYSUBTYPE<<16));

A client-supplied hook function for dumping the objects stored in Client blocks can be installed using _CrtSetDumpClient, and will then be called whenever a Client block is dumped by a debug function. Also, _CrtDoForAllClientObjects can be used to call a given function supplied by the application for every Client block in the debug heap.

_FREE_BLOCK

Normally, blocks that are freed are removed from the list. To check that freed memory is not still being written to, or to simulate low memory conditions, you can choose to keep freed blocks on the linked list, marked as Free and filled with a known byte value (currently 0xDD).

_IGNORE_BLOCK

It is possible to turn off the debug heap operations for a period of time. During this time, memory blocks are kept on the list, but are marked as Ignore blocks.


Using the Debug Heap

To use the debug heap, link the debug build of your application with a debug version of the C run-time library. All calls to heap functions such as malloc, free, calloc, realloc, new, and delete resolve to debug versions of those functions that operate in the debug heap. When you free a memory block, the debug heap automatically checks the integrity of the buffers on either side of your allocated area and issues an error report if overwriting has occurred.

Many of the debug heap’s features, however, must be accessed from within your code. You can use a call to _CrtCheckMemory, for example, to check the heap’s integrity at any point. This function inspects every memory block in the heap, verifies that the memory block header information is valid, and confirms that the buffers have not been modified. You can control how the debug heap keeps track of allocations using an internal flag, _crtDbgFlag, which can be read and set using the _CrtSetDbgFlag function. By changing this flag, you can instruct the debug heap to check for memory leaks when the program exits, and report any leaks that are detected. Similarly, you can specify that freed memory blocks not be removed from the linked list, to simulate low-memory situations. When the heap is checked, these freed blocks are inspected in their entirety to ensure that they have not been disturbed.

The _crtDbgFlag flag contains the following bit fields:

Bit Field | Value | Description
_CRTDBG_ALLOC_MEM_DF | On | Turns on debug allocation. When this bit is off, allocations remain chained together but their block type is _IGNORE_BLOCK.
_CRTDBG_DELAY_FREE_MEM_DF | Off | Prevents memory from actually being freed, as for simulating low-memory conditions. When this bit is on, freed blocks are kept in the debug heap’s linked list but are marked as _FREE_BLOCK and filled with a special byte value.
_CRTDBG_CHECK_ALWAYS_DF | Off | Causes _CrtCheckMemory to be called at every allocation and deallocation. This slows execution, but catches errors quickly.
_CRTDBG_CHECK_CRT_DF | Off | Causes blocks marked as type _CRT_BLOCK to be included in leak-detection and state-difference operations. When this bit is off, the memory used internally by the run-time library is ignored during such operations.
_CRTDBG_LEAK_CHECK_DF | Off | Causes leak checking to be performed at program exit via a call to _CrtDumpMemoryLeaks. An error report is generated if the application has failed to free all the memory that it allocated.

To change one or more of these bit fields and create a new state for the flag, follow these steps:

  1. Call _CrtSetDbgFlag with the newFlag parameter set to _CRTDBG_REPORT_FLAG to obtain the current _crtDbgFlag state and store the returned value in a temporary variable.

  2. Turn on any bits by OR-ing (bitwise | symbol) the temporary variable with the corresponding bitmasks (represented in the application code by manifest constants).

  3. Turn off the other bits by AND-ing (bitwise & symbol) the variable with a NOT (bitwise ~ symbol) of the appropriate bitmasks.

  4. Call _CrtSetDbgFlag with the newFlag parameter set to the value stored in the temporary variable to create the new state for _crtDbgFlag.

For example, the following lines of code turn on automatic leak detection and turn off checking for blocks of type _CRT_BLOCK:

// Get current flag
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );

// Turn on leak-checking bit
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;

// Turn off CRT block checking bit
tmpFlag &= ~_CRTDBG_CHECK_CRT_DF;

// Set flag to the new value
_CrtSetDbgFlag( tmpFlag );


Heap State Reporting Functions

Several new functions report the contents of the debug heap at a given moment. To capture a summary snapshot of the state of the heap at a given time, use the _CrtMemState structure defined in CRTDBG.H:

typedef struct _CrtMemState
{
// Pointer to the most recently allocated block:
   struct _CrtMemBlockHeader * pBlockHeader;
// A counter for each of the 5 types of block:
   long lCounts[_MAX_BLOCKS];
// Total bytes allocated in each block type:
   long lSizes[_MAX_BLOCKS];
// The most bytes allocated at a time up to now:
   long lHighWaterCount;
// The total bytes allocated at present:
   long lTotalCount;
} _CrtMemState;

This structure saves a pointer to the first (most recently allocated) block in the debug heap’s linked list. Then, in two arrays, it records how many of each type of memory block (_NORMAL_BLOCK, _CLIENT_BLOCK, _FREE_BLOCK, and so forth) there are in the list, and the number of bytes allocated in each type of block. Finally, it records the highest number of bytes allocated in the heap as a whole up to that point, and the number of bytes currently allocated.

The following functions report the state and contents of the heap, and use the information to help detect memory leaks and other problems:

Function | Description
_CrtMemCheckpoint | Saves a snapshot of the heap in a _CrtMemState structure supplied by the application.
_CrtMemDifference | Compares two memory state structures, saves the difference between them in a third state structure, and returns TRUE if the two states are different.
_CrtMemDumpStatistics | Dumps a given _CrtMemState structure. The structure may contain a snapshot of the state of the debug heap at a given moment, or the difference between two snapshots. “Dumping” means reporting the data in a form that a person can understand.
_CrtMemDumpAllObjectsSince | Dumps information about all objects allocated since a given snapshot was taken of the heap, or from the start of execution. Every time it dumps a _CLIENT_BLOCK block, it calls a hook function supplied by the application, if one has been installed using _CrtSetDumpClient.
_CrtDumpMemoryLeaks | Determines whether any memory leaks occurred since the start of program execution, and if so, it dumps all allocated objects. Every time it dumps a _CLIENT_BLOCK block, it calls a hook function supplied by the application, if one has been installed using _CrtSetDumpClient.


Tracking Heap Allocation Requests

Although pinpointing the source file name and line number at which an assert or reporting macro executes is often very useful in locating the cause of a problem, the same is not as likely to be true of heap allocation functions. While macros can be inserted at many appropriate points in an application’s logic tree, an allocation is often buried in a special routine that is called from many different places at many different times. The question is usually not what line of code made a bad allocation, but rather which one of the thousands of allocations made by that line of code was bad, and why.

The simplest way to identify the specific heap allocation call that went bad is to take advantage of the unique allocation request number associated with each block in the debug heap. When information about a block is reported by one of the dump functions, this allocation request number is enclosed in curly brackets (for example, “{36}”).

Once you know the allocation request number of an improperly allocated block, you can pass this number to _CrtSetBreakAlloc to create a breakpoint. Execution will break just prior to allocating the block, and you can backtrack to determine what routine was responsible for the bad call. To avoid recompiling, you can accomplish the same thing in the debugger by setting _crtBreakAlloc to the allocation request number you are interested in.

A somewhat more complicated approach is to create debug versions of your own allocation routines, comparable to the _dbg versions of the heap allocation functions. You can then pass source file and line number arguments through to the underlying heap allocation routines, and you will immediately be able to see where a bad allocation originated.

For example, suppose your application contains a commonly used routine similar to the following:

int addNewRecord(struct RecStruct * prevRecord,
                 int recType, int recAccess)
{
   /* ...code omitted through actual allocation... */
   if ((newRec = malloc(recSize)) == NULL)
   /* ... rest of routine omitted too ... */
}

In a header file, you could add code such as the following:

#ifdef _DEBUG
#define  addNewRecord(p, t, a) \
         addNewRecord(p, t, a, __FILE__, __LINE__)
#endif

Next, you could change the allocation in your record-creation routine as follows:

int addNewRecord(struct RecStruct *prevRecord,
                 int recType, int recAccess
#ifdef _DEBUG
               , const char *srcFile, int srcLine
#endif
   )
{
   /* ... code omitted through actual allocation ... */
   if ((newRec = _malloc_dbg(recSize, _NORMAL_BLOCK,
        srcFile, scrLine)) == NULL)
   /* ... rest of routine omitted too ... */
}

Now the source file name and line number where addNewRecord was called will be stored in each resulting block allocated in the debug heap and will be reported when that block is examined.


Writing Your Own Debug Hook Functions

This section covers the following topics:

  • Client Block Hook Functions

  • Allocation Hook Functions

  • Allocation Hooks Should Ignore C Run-Time Memory Allocations

  • Report Hook Functions

  • Sample: Hook Function C Run-Time Application


Client Block Hook Functions

If you are interested in validating or reporting the contents of the data that you are storing in _CLIENT_BLOCK blocks, you can write a function specifically for this purpose. The function that you write must have a prototype similar to the following, as defined in CRTDBG.H:

void YourClientDump(void *, size_t)

In other words, your hook function should accept a void pointer to the beginning of the user’s topic of the allocation block, together with a size_t type value indicating the size of the allocation, and return void. Other than that, its contents are up to you.

Once you have installed it using _CrtSetDumpClient, your hook function will be called every time a _CLIENT_BLOCK block is dumped.

The pointer to your function that you pass to _CrtSetDumpClient is of type _CRT_DUMP_CLIENT, as defined in CRTDBG.H:

typedef void (__cdecl *_CRT_DUMP_CLIENT)
   (void *, size_t);


Allocation Hook Functions

An allocation hook function, installed using _CrtSetAllocHook, is called every time memory is allocated, re-allocated, or freed. This type of hook can be used for many different purposes. Use it to test how an application handles insufficient memory situations, for example, or to examine allocation patterns, or to log allocation information for later analysis. Be aware of the restriction described below about using C run-time library functions in an allocation hook function.

An allocation hook function should have a prototype like the following:

int YourAllocHook(int nAllocType, void *pvData,
      size_t nSize, int nBlockUse, long lRequest,
      const unsigned char * szFileName, int nLine )

The pointer that you pass to _CrtSetAllocHook is of type _CRT_ALLOC_HOOK, as defined in CRTDBG.H:

typedef int (__cdecl * _CRT_ALLOC_HOOK)
   (int, void *, size_t, int, long, const char *, int);

When the run-time library calls your hook, the nAllocType argument indicates what allocation operation is about to be performed (_HOOK_ALLOC, _HOOK_REALLOC, or _HOOK_FREE). In the case of a free or a reallocation, pvData contains a pointer to the user topic of the block about to be freed. However, in the case of an allocation, this pointer is null, because the allocation has not yet occurred. The remaining arguments contain the size of the allocation in question, its block type, the sequential request number associated with it, and a pointer to the file name and line number in which the allocation was made, if available. After the hook function performs whatever analysis and other tasks its author wants, it must return either TRUE, indicating that the allocation operation can continue, or FALSE, indicating that the operation should fail. A simple hook of this type might check the amount of memory allocated so far, and return FALSE if that amount exceeded a small limit. The application would then experience the kind of allocation errors that would normally occur only when available memory was very low. More complex hooks might keep track of allocation patterns, analyze memory use, or report when specific situations occur.


Allocation Hooks Should Ignore C Run-time Memory Allocations

A very important restriction on allocation hook functions is that they must explicitly ignore _CRT_BLOCK blocks (the memory allocations made internally by C run-time library functions) if they make any calls to C run-time library functions that allocate internal memory. The _CRT_BLOCK blocks can be ignored by including code such as the following at the beginning of your allocation hook function:

   if ( nBlockUse == _CRT_BLOCK )
      return( TRUE );

If your allocation hook does not ignore _CRT_BLOCK blocks, then any C run-time library function called in your hook can trap the program in an endless loop. For example, printf makes an internal allocation. If your hook code calls printf, then the resulting allocation will cause your hook to be called again, which will call printf again, and so on until the stack overflows. If you need to report _CRT_BLOCK allocation operations, one way to circumvent this restriction is to use Windows API functions, rather than C run-time functions, for formatting and output . Because the Windows APIs do not use the C run-time library heap, they will not trap your allocation hook in an endless loop.

If you examine the run-time library source files, you will see that the default allocation hook function, CrtDefaultAllocHook (which simply returns TRUE), is located in a separate file of its own, DBGHOOK.C. If you want your allocation hook to be called even for the allocations made by the run-time startup code that is executed before your application’s main function, you can replace this default function with one of your own, instead of using _CrtSetAllocHook.


Report Hook Functions

A report hook function, installed using _CrtSetReportHook, is called every time _CrtDbgReport generates a debug report. You can use it, among other things, for filtering reports to focus on specific types of allocations. A report hook function should have a prototype like the following:

int YourReportHook(int nRptType, char *szMsg, int *retVal);

The pointer that you pass to _CrtSetReportHook is of type _CRT_REPORT_HOOK, as defined in CRTDBG.H:

typedef int (__cdecl *_CRT_REPORT_HOOK)(int, char *, int *);

When the run-time library calls your hook function, the nRptType argument contains the category of the report (_CRT_WARN, _CRT_ERROR, or _CRT_ASSERT), szMsg contains a pointer to a fully assembled report message string, and retVal specifies the value that should be returned by _CrtDbgReport. If the hook handles the message in question completely, so that no further reporting is required, it should return FALSE. If it returns TRUE, then _CrtDbgReport will report the message in the normal way.


Sample: Hook Function C Run-Time Application

This program illustrates several ways to use debugging hook functions with the new debug versions of the C run-time library. To add some realism, it has a few elements of an actual application, including two bugs.

The program stores birthdate information in a linked list of Client blocks. A Client-dump hook function validates the birthday data and reports the contents of the Client blocks. An allocation hook function logs heap operations to a text file, and the report hook function logs selected reports to the same text file.

Note that the allocation hook function explicitly excludes CRT blocks (the memory allocated internally by the C run-time library) from its log. The hook function uses fprintf to write to the log file, and fprintf allocates a CRT block. If CRT blocks were not excluded in this case, an endless loop would overflow the stack: fprintf would cause the hook function to be called, the hook would in turn call fprintf, which would in turn cause the hook to be called again, and so forth.

To be able to report CRT-type blocks in your allocation hook, Windows API functions could be used instead of C run-time functions. Because the Windows APIs do not use the CRT heap, they would not trap the hook in an endless loop.

The debug heap catches two bugs and a data error in the second example. One bug is that the birthday name field is not large enough to hold several of the test names. The field should be larger, and strncpy should be used instead of strcpy. The second bug is that the ‘while’ loop in the printRecords function should not end until the HeadPtr itself is equal to null. This bug results not only in an incomplete display of birthdays, but also in a memory leak. Finally, Gauss’ birthday should be April 30, not April 32.

Build this sample as a Win32 console application. Your command line should look like the following:

cl -D_DEBUG /MTd -Od -Zi -W3 sample.c -link -verbose:lib -debug:full

In this example, sample.c is the name of the sample application, and you should substitute the name of the sample file. In console applications such as the following examples, debugging is complicated by the fact that errors do not interrupt execution of the application, as they normally would when directed to a message window.

/******************************************************
 *  EXAMPLE  2                                        *
 *                                                    *
 *  This application illustrates several ways to use  *
 *  debugging hook functions with the new debug       *
 *  versions of the C runtime libraries. To add some  *
 *  realism, it has a few elements of an actual       *
 *  application, including two bugs.                  *
 *                                                    *
 *  The program stores birthdate information in a     *
 *  linked list of Client blocks. A Client-dump hook  *
 *  function validates the birthday data and reports  *
 *  the contents of the Client blocks. An allocation  *
 *  hook function logs heap operations to a text file,*
 *  and the report hook function logs reports to the  *
 *  same text file.                                   *
 *                                                    *
 *  NOTE: The allocation hook function explicitly     *
 *  excludes CRT blocks (the memory allocated         *
 *  internally by the C runtime library) from its log.*
 *  It is important to understand why! The hook       *
 *  function uses fprintf( ) to write to the log file,*
 *  and fprintf( ) allocates a CRT block. If CRT      *
 *  blocks   were not excluded in this case, an       *
 *  endless loop would be created in which fprintf( ) *
 *  would cause the hook function to be called, and   *
 *  the hook would in turn call fprintf( ), which     *
 *  would cause the hook to be called again, and so   *
 *  on. The moral is:                                 *
 *                                                    *
 *  IF YOUR ALLOCATION HOOK USES ANY C RUNTIME        *
 *  FUNCTION THAT ALLOCATES MEMORY, THE HOOK MUST     *
 *  IGNORE CRT-TYPE ALLOCATION OPERATIONS!            *
 *                                                    *
 *  HINT: If you want to be able to report CRT-type   *
 *  blocks in your allocation hook, use Windows API   *
 *  functions for formatting and output, instead of C *
 *  runtime functions. Since the Windows APIs do not  *
 *  use the CRT heap, they will not trap your hook in *
 *  an endless loop.                                  *
 *                                                    *
 *  BUGS: There are two bugs in the program below,    *
 *  which the debug heap features identify in several *
 *  ways. One bug is that the birthDay.Name field is  *
 *  not large enough to hold several of the test      *
 *  names. The field should be larger, and strncpy( ) *
 *  should be used in place of strcpy( ). The second  *
 *  bug is that the while( ) loop in the              *
 *  printRecords( ) function should not end until     *
 *  HeadPtr itself == NULL. This bug results not only *
 *  in an incomplete display of birthdays, but also in*
 *  a memory leak. In addition to these two bugs,     *
 *  Gauss' birthday data is out of range (April 30,   *
 *  not 32).                                          *
******************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <crtdbg.h>

/******************************************************
 *  DATA DECLARATIONS AND DEFINES                     *
******************************************************/

// The following arrays provide test data for the
// example program:
const char * Names[] =
{
   "George Washington",
   "Thomas Jefferson",
   "Carl Friedrich Gauss",
   "Ludwig van Beethoven",
   "Thomas Carlyle"
} ;

const int Dates[] =
{
   1732,  2, 11,
   1743,  4, 13,
   1777,  4, 32,
   1795, 12,  4,
   1770, 12, 16
} ;

#define  TEST_RECS            5
// A generic sort of linked-list data structure, in
// this case for birthdays:
typedef struct BirthdayStruct
{
   struct BirthdayStruct * NextRec;
   int   Year;
   int   Month;
   int   Day;
   char  Name[20];
} birthDay;

birthDay * HeadPtr;
birthDay * TailPtr;

#define  FILE_IO_ERROR        0
#define  OUT_OF_MEMORY        1

#define  TRUE                 7
#define  FALSE                0

// Macros for setting or clearing bits in the CRT debug flag
#ifdef _DEBUG
#define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

/******************************************************
 *  SPECIAL-PURPOSE ROUTINES                          *
******************************************************/

/* ERROR HANDLER
  Handling serious errors gracefully is a real test of
  craftsmanship. This function is just a stub; it
  doesn't really handle errors.
*/
void FatalError( int ErrType )
{
   exit( 1 );
}

/* MEMORY ALLOCATION FUNCTION
  The createRecord function allocates memory for a new
  birthday record, fills in the structure members, and
  then adds the record to a linked list. In debug
  builds, it makes these allocations in Client blocks.
  If memory is not available, it calls the error
  handler.
*/
void createRecord(
   const int    Year,
   const int    Month,
   const int    Day,
   const char * Name
#ifdef _DEBUG
,  const unsigned char * szFileName, int nLine
#endif
   )
{
   birthDay * ptr;
   size_t n;

   n = sizeof( struct BirthdayStruct );
   ptr = (birthDay *) _malloc_dbg( n, _CLIENT_BLOCK, szFileName, nLine );
   if( ptr == NULL )
      FatalError( OUT_OF_MEMORY );
   ptr->Year = Year;
   ptr->Month = Month;
   ptr->Day = Day;
   strcpy( ptr->Name, Name );

   ptr->NextRec = NULL;
   if ( HeadPtr == NULL ) // 1st record in linked list?
      HeadPtr = ptr;
   else
      TailPtr->NextRec = ptr;
   TailPtr = ptr;
}

/* BIRTHDAY DISPLAY FUNCTION
  This function traverses the linked list, displays the
  birthday data, and then frees the memory blocks used
  to store the birthdays.
*/
void printRecords( )
{
   birthDay * ptr;
   char *months[] = {
      "", "January", "February", "March", "April", "May", "June", "July",
      "August", "September", "October", "November", "December" };

   if ( HeadPtr == NULL ) // Do nothing if list empty
      return;

   printf( "\n\nThis is the birthday list:\n" );
   while ( HeadPtr->NextRec != NULL )
   {
      printf( "   %s was born on %s %d, %d.\n",
              HeadPtr->Name, months[HeadPtr->Month], HeadPtr->Day, HeadPtr->Year );
      ptr = HeadPtr->NextRec;
      _free_dbg( HeadPtr, _CLIENT_BLOCK );
      HeadPtr = ptr;
   }
}

/******************************************************
 *  DEBUG C RUNTIME LIBRARY HOOK FUNCTIONS AND DEFINES*
******************************************************/
#ifdef _DEBUG
#define  createRecord(a, b, c, d) \
         createRecord(a, b, c, d, __FILE__, __LINE__)
FILE *logFile;                // Used to log allocation information
const char lineStr[] = { "---------------------------------------\
--------------------------------------\n"  };

/* CLIENT DUMP HOOK FUNCTION
   A hook function for dumping a Client block usually
   reports some or all of the contents of the block in
   question.  The function below also checks the data
   in several ways, and reports corruption or
   inconsistency as an assertion failure.
*/
void __cdecl MyDumpClientHook(
   void * pUserData,
   size_t nBytes
   )
{
   birthDay * bday;

   bday = (birthDay *) pUserData;

   _RPT4( _CRT_WARN, "   The birthday of %s is %d/%d/%d.\n",
          bday->Name, bday->Month, bday->Day, bday->Year );
   _ASSERTE( ( bday->Day > 0 ) && ( bday->Day < 32 ) );
   _ASSERTE( ( bday->Month > 0 ) && ( bday->Month < 13 ) );
   _ASSERTE( ( bday->Year > 0 ) && ( bday->Year < 1996 ) );
}

/* ALLOCATION HOOK FUNCTION
   An allocation hook function can have many, many
   different uses. This one simply logs each allocation
   operation in a file.
*/
int __cdecl MyAllocHook(
   int      nAllocType,
   void   * pvData,
   size_t   nSize,
   int      nBlockUse,
   long     lRequest,
   const unsigned char * szFileName,
   int      nLine
   )
{
   char *operation[] = { "", "allocating", "re-allocating", "freeing" };
   char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };

   if ( nBlockUse == _CRT_BLOCK ) // Ignore internal
                                  // C runtime library
                                  // allocations
      return( TRUE );

   _ASSERT( ( nAllocType > 0 ) && ( nAllocType < 4 ) );
   _ASSERT( ( nBlockUse >= 0 ) && ( nBlockUse < 5 ) );

   fprintf( logFile,
            "Memory operation in %s, line %d: %s a %d-byte '%s' block (# %ld)\n",
            szFileName, nLine, operation[nAllocType], nSize,
            blockType[nBlockUse], lRequest );
   if ( pvData != NULL )
      fprintf( logFile, " at %X", pvData );

   return( TRUE );   // Let memory operation proceed
}

/* REPORT HOOK FUNCTION
   Again, report hook functions can serve a very wide
   variety of purposes. This one logs error and
   assertion failure debug reports in the log file,
   along with 'Damage' reports about overwritten
   memory.

   By setting the retVal parameter to zero, we are
   instructing _CrtDbgReport to return zero, which
   causes execution to continue. If we want the
   function to start the debugger, we should have
   _CrtDbgReport return one.
*/
int MyReportHook(
   int   nRptType,
   char *szMsg,
   int  *retVal
   )
{
   char *RptTypes[] = { "Warning", "Error", "Assert" };

   if ( ( nRptType > 0 ) || ( strstr( szMsg, "DAMAGE" ) ) )
      fprintf( logFile, "%s: %s", RptTypes[nRptType], szMsg );

   retVal = 0;

   return( TRUE );  // Allow report to be made as usual

}
#endif              // End of #ifdef _DEBUG

/******************************************************
 *  MAIN FUNCTION                                     *
******************************************************/
void main( )
{
   int i, j;

#ifdef _DEBUG
   _CrtMemState checkPt1;
   char timeStr[10], dateStr[10];         // Used to set up log file

   // Send all reports to STDOUT, since this example is
   // a console app
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   // Set the debug heap to report memory leaks when
   // the process terminates,and to keep freed blocks
   // in the linked list.
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF );

   // Open a log file for the hook functions to use
   logFile = fopen( "MEM-LOG.TXT", "w" );
   if ( logFile == NULL )
      FatalError( FILE_IO_ERROR );
   _strtime( timeStr );
   _strdate( dateStr );
   fprintf( logFile,
            "Memory Allocation Log File for Example Program, run at %s on %s.\n",
            timeStr, dateStr );
   fputs( lineStr, logFile );

   // Install the hook functions
   _CrtSetDumpClient( MyDumpClientHook );
   _CrtSetAllocHook( MyAllocHook );
   _CrtSetReportHook( MyReportHook );

#endif                     // End of #ifdef _DEBUG

   HeadPtr = NULL;

   // Create a trial birthday record.
   createRecord( 1749, 3, 23, "Pierre de Laplace" );

   // Check the debug heap, and dump the new birthday
   // record. --Note that debug C runtime library
   // functions such as _CrtCheckMemory( ) and
   // _CrtMemDumpAllObjectsSince( ) automatically
   // disappear in a release build.
   _CrtMemDumpAllObjectsSince( NULL );
   _CrtCheckMemory( );
   _CrtMemCheckpoint( &checkPt1 );

   // Since it all works so far, create more records
   for ( i = 0, j = 0; i < TEST_RECS; i++, j+=3 )
      createRecord( Dates[j], Dates[j+1], Dates[j+2], Names[i] );

   // Examine the results
   _CrtMemDumpAllObjectsSince( &checkPt1 );
   _CrtMemCheckpoint( &checkPt1 );
   _CrtMemDumpStatistics( &checkPt1 );
   _CrtCheckMemory( );

   // This fflush needs to be removed...
   fflush( logFile );

   // Now try displaying the records, which frees the
   // memory being used
   printRecords( );

   // OK, time to go. Did I forget to turn out any
   // lights? I could check explicitly using
   // _CrtDumpMemoryLeaks( ), but I have set
   // _CRTDBG_LEAK_CHECK_DF, so the C runtime library
   // debug heap will automatically alert me at exit of
   // any memory leaks.

#ifdef _DEBUG
   fclose( logFile );
#endif
}

Output

Screen output:

Dumping objects ->
C:\DEV\EXAMPLE2.C(327) : {13} client block at 0x00661B38, subtype 0, 36 bytes long:
   The birthday of Pierre de Laplace is 3/23/1749.
Object dump complete.
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
C:\DEV\EXAMPLE2.C(338) : {17} client block at 0x00661C68, subtype 0, 36 bytes long:
   The birthday of Ludwig van Beethoven is 12/4/1795.
C:\DEV\EXAMPLE2.C(338) : {16} client block at 0x00661C1C, subtype 0, 36 bytes long:
   The birthday of Carl Friedrich Gauss is 4/32/1777.
C:\DEV\EXAMPLE2.C(219) : Assertion failed: ( bday->Day > 0 ) && ( bday->Day < 32 )
C:\DEV\EXAMPLE2.C(338) : {15} client block at 0x00661BD0, subtype 0, 36 bytes long:
   The birthday of Thomas Jefferson is 4/13/1743.
C:\DEV\EXAMPLE2.C(338) : {14} client block at 0x00661B84, subtype 0, 36 bytes long:
   The birthday of George Washington is 2/11/1732.
Object dump complete.
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
6442 bytes in 12 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
216 bytes in 6 (null) Blocks.
Largest number used: 6658 bytes.
Total allocations: 6658 bytes.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C68 is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C1C is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.

This is the birthday list:
   Pierre de Laplace was born on March 23, 1749.
   George Washington was born on February 11, 1732.
   Thomas Jefferson was born on April 13, 1743.
   Carl Friedrich Gauss was born on April 32, 1777.
   Ludwig van Beethoven was born on December 4, 1795.
Detected memory leaks!
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
Object dump complete.

Log file output:

Memory Allocation Log File for Example Program, run at 14:11:01 on 04/28/95.
-----------------------------------------------------------------------------
Memory operation in C:\DEV\EXAMPLE2.C, line 327:
                                   allocating a 36-byte 'Client' block (# 13)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 14)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 15)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 16)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 17)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 18)
Assert: C:\DEV\EXAMPLE2.C(219) : Assertion failed:
                                    ( bday->Day > 0 ) && ( bday->Day < 32 )
Warning: DAMAGE: after (null) block (#17) at 0x00661C68.
Warning: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661B38Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661B84Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661BD0Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661C1CError: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661C68Error: DAMAGE: after (null) block (#17) at 0x00661C68.


Using C Run-Time Library Debugging Support

This section covers the following topics:

  • C Run-Time Library Debugging Support

  • Source Code for the C Run-Time Functions

  • C Run-Time Debug Libraries

  • Debug Reporting Functions of the C Run-Time Library


C Run-Time Library Debugging Support

Visual C++ adds extensive debugging support to the C run-time library, letting you step directly into run-time functions when debugging an application. The library also provides a variety of tools to keep track of heap allocations, locate memory leaks, and track down other memory-related problems.

Much of the heap-checking technology included in the debug version of the C run-time library has been moved from the Microsoft Foundation Class library. To use the heap-checking technology, debug builds of MFC applications must now be linked with a debug version of the run-time library.

The library contains debug reporting functions, such as _CrtDbgReport and _CrtIsValidPointer; macros for verification and reporting, such as _ASSERT and _RPTn; functions that use a debug heap, such as debug versions of malloc, free, calloc, realloc, new and delete; and heap-monitoring functions, such as _CrtCheckMemory , _CrtDumpMemoryLeaks. It also includes functions, such as _CrtSetDumpClient and _CrtSetAllocHook, allow you to write and install your own hook functions with special features you need when debugging a complex application.

The C run-time debug functions are available for Windows 95 and Windows NT.


Source Code for the C Run-Time Functions

Visual C++ introduces source code availability for most of the C run-time library functions. You can now use the debugger to step into the source code for the run-time functions by linking your application with a debug version of the run-time library. During the debugging process, source code availability allows you to confirm that the run-time functions are working as expected, check for bad parameters and memory states, and examine your code for other errors.

Because the C run-time library has been designed to achieve the highest possible performance, the release versions of the functions rarely verify parameters, confirm internal states, or perform other checking that might slow program execution. As a result, an incorrect call to a run-time function can result in serious problems accompanied by too little information to resolve the situation. For example, passing a bad pointer to the strcpy function usually results in a simple “General Protection Fault” error message. The ability to step into the run-time source code allows you to control the type of verifications and how many to perform, as well as the opportunity to trace through the execution of your application to resolve specific problems.

The Setup program gives you the option of installing the C run-time library source code on your hard disk. Even if you choose to leave the source files on the compact disc, you can step into run-time functions while you are debugging, as long as the compact disc is loaded in the drive.

The main definitions and macros that control the debugging process are contained in the CRTDBG.H header file. Experienced programmers should examine this file to understand how to take full advantage of the flexibility that the new debug libraries offer.

Source code for the debug run-time functions is contained in source files whose names begin with dbg. Source code for the other C run-time functions is contained in files whose names reflect the function names. However, Microsoft considers some run-time technology to be proprietary and does not provide source code for the exception handling, floating point, and a few other routines. For a complete list of these routines, see Debug Routines.


C Run-Time Debug Libraries

The following table lists the debug versions of the C run-time library files, along with their associated compiler options and environment variables. For a list of the release versions of these libraries, see C Run-Time Libraries.

Prior to Visual C++ 4.2, the C run-time libraries contained the iostream library functions. In Visual C++ 4.2, the old iostream library functions were removed from LIBCD.LIB, LIBCMTD.LIB, and MSVCRTD.LIB. This change was made because the Standard C++ library was added to Visual C++, and it contains a new set of iostream libraries.

Two sets of iostream functions are now included in Visual C++. The old iostream functions now exist in their own libraries: LIBCID.LIB, LIBCIMTD.LIB, and MSVCIRTD.LIB. The new iostream functions, as well as many other new functions, exist in the Standard C++ libraries: LIBCPD.LIB, LIBCPMTD.LIB, and MSVCPRTD.LIB.

The Standard C++ library and the old iostream library are incompatible and only one of them can be linked with your project. See the Standard C++ Library Overview and Make the Old iostream Library the Default for details.

When you build a debug version of your project, one of the basic C run-time debug libraries (LIBCD.LIB, LIBCMTD.LIB, and MSVCRTD.LIB) is linked by default, depending on the compiler option you choose (single-threaded, multithreaded, or DLL). Depending on the headers you use in your code, a debug library from the Standard C++ libraries or one from the old iostream libraries may also be linked.

  • If you include a Standard C++ library header in your code, a Standard C++ library will be linked in automatically by Visual C++ at compile time. For example:
   #include <ios>
  • If you include an old iostream library header, an old iostream library will be linked in automatically by Visual C++ at compile time. For example:
   #include <ios.h>

Note that headers from the Standard C++ library and the old iostream library cannot be mixed.

Headers determine whether a Standard C++ library, an old iostream library, or neither will be linked. Compiler options determine which of the libraries to be linked is the default (single-threaded, multithreaded, or DLL). When a specific library compiler option is defined, that library is considered to be the default and its environment variables are automatically defined.

C Run-Time Debug Library (without iostream) | Characteristics | Option | Defined
LIBCD.LIB | Single-threaded, static link | /MLd | _DEBUG
LIBCMTD.LIB | Multithreaded, static link | /MTd | _DEBUG, _MT
MSVCRTD.LIB | Multithreaded, dynamic link (import library for MSVCRTD.DLL)1 | /MDd | _DEBUG, _MT, _DLL
1 In place of the “x” in the DLL name, substitute the major version numeral of Visual C++ that you are using. For example, if you are using Visual C++ version 4, then the library name would be MSVCR40D.DLL.

Standard C++ Debug Library | Characteristics | Option | Defined
LIBCPD.LIB | Single-threaded, static link | /MLd | _DEBUG
LIBCPMTD.LIB | Multithreaded, static link | /MTd | _DEBUG, _MT
MSVCPRTD.LIB | Multithreaded, dynamic link (import library for MSVCRTD.DLL) | /MDd | _DEBUG, _MT, _DLL

iostream Debug Library | Characteristics | Option | Defined
LIBCID.LIB | Single threaded, static link | /MLd | _DEBUG
LIBCIMTD.LIB | Multithreaded, static link | /MTd | _DEBUG, _MT
MSVCIRTD.LIB | Multithreaded, dynamic link (import library for MSVCIRTD.DLL) | /MDd | _DEBUG, _MT, _DLL

The debug versions of the library functions differ from the release versions mainly in that debug information was included when they were compiled (using the /Z7 or /Zi compiler option), optimization was turned off, and source code is available. A few of the debug library functions also contain asserts that verify parameter validity.

Using one of these debug libraries is as simple as linking it to your application with the /DEBUG:FULL linker option set. You can then step directly into almost any run-time function call.


Debug Reporting Functions of the C Run-Time Library

The run-time library includes three new debug reporting functions that provide extensive flexibility for reporting warnings and errors during execution of a debug build of an application. The main reporting function is _CrtDbgReport. Two configuration functions, _CrtSetReportMode and _CrtSetReportFile, can be used at any point to specify the destinations to which different kinds of reports will be sent.

Function | Destination
_CrtDbgReport | Reports from within an application. Set the report destination(s) by specifying its category (_CRT_WARN, _CRT_ERROR, and _CRT_ASSERT). The report may also include a message string, a source file name and line number, and one or more arguments to be formatted into the message string.
_ _CrtSetReportMode | Specifies the general destination(s) to which a given category of report output should be sent. The three categories of report output are _CRT_WARN, _CRT_ERROR, and _CRT_ASSERT. Possible destinations include the debugger, a message window, and/or a file or stream.
_CrtSetReportFile | Identifies a specific file or stream when _CrtSetReportMode has specified that a given category of report output will be directed to a file or stream.

For detailed information about the syntax and usage of these functions, see the Debug Routines.

Debug reports can be assigned to three different categories, depending on the urgency of the messages they contain:

_CRT_WARN

Warnings, messages, and information not needing immediate attention.

_CRT_ERROR

Errors, unrecoverable problems, and information needing immediate attention.

_CRT_ASSERT

Assertion failure (an asserted expression evaluated as FALSE).

A different destination can be specified for each of these report categories. Usually one destination is sufficient for a category, but each category can be sent to more than one destination. Up to three of the following bit-flags can be combined in the reportMode argument passed to _CrtReportMode to specify the destination(s) for a given report category:

_CRTDBG_MODE_DEBUG

Reports are sent to the debugger or debug monitor using the Win32 OutputDebugString API.

_CRTDBG_MODE_FILE

Reports are sent to a file (including the stderr and stdout streams) using the Win32 WriteFile API.

_CRTDBG_MODE_WNDW

Reports are sent to a message window using the Win32 MessageBox API.

To turn off a given category of report, pass _CrtReportMode a reportMode value of zero.

By default, errors and assertion failures are directed to a message window, because they generally signal serious problems that you want to know about right away. Warnings from Windows applications are sent to the debugger, and warnings from console applications are directed to stderr. You only need to use the _CrtSetReport... functions when you want to change these destinations. For example, the following code causes assertion failures to be sent both to a message window and to stderr:

_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE |
                   _CRTDBG_MODE_WNDW );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );

To send a debug report, you use _CrtDbgReport and control the destination by specifying the category of the report. If you need more flexibility, you can write your own reporting function and hook it into the C run-time library reporting mechanism using _CrtSetReportHook.

While messages that go to a file or the debugger are generally single lines that can include a file name and line number, the message window contains considerably more information. It identifies the error and the program more fully, along with message text, and can also display a file name and line number. Assert message windows contain additional information particular to asserts.

All message windows display Abort/Retry/Ignore buttons. Clicking Abort causes the program to stop execution immediately, Ignore causes execution to continue, and Retry invokes the debugger, provided that Just-in-time debugging is enabled. Clicking Ignore when an error condition exists often results in undefined behavior.


Using MFC Debugging Support

This section covers the following topics:

  • MFC Debugging Support

  • Diagnostic Features

  • Using the ASSERT_VALID Macro

  • Tracking Memory Allocations

  • Detecting Memory Leaks

  • Using Object Dumps

  • How Can I View the Call Stack After an MFC Assert?


MFC Debugging Support

The Microsoft Foundation Class Library (MFC) and Visual C++ help you debug your applications in a variety of ways. This topic presents a few useful general debugging techniques, followed by more detailed debugging topics.

The Microsoft Foundation Class Library (MFC) contains many diagnostic features to help debug your program during development, such as the Dump and AssertValid member functions, the TRACE and ASSERT macros, the AfxEnableMemoryTracking and AfxDebugBreak global functions, and the CMemoryState class to detect memory leaks.

Because diagnostics slow down and interrupt your application, they are not suitable for a release version. When you are developing your program, you typically build a Win32 Debug version of your program and link with the debug version of MFC. Once the program is completed and debugged, you build a Win32 Release version and link with the release version of MFC. You can easily switch between Win32 Debug and Win32 Release by setting the Select Active Configuration droplist.

Following are several techniques for debugging your MFC application:

  • Before you start a debugging session (or as soon as possible after you start), arrange the debugger and the program you are debugging on the screen so that neither overlaps the other. Otherwise, there may be situations in which the debugger completely obscures the program being debugged.

  • Turn on Multiple application debugging from the TRACER application when you are debugging an application and one or more DLLs. The Multiple application debugging option prefixes each trace statement with the name of the application that generated it. TRACER can be found in the BIN directory, and an icon for it is installed in the Microsoft Visual C++ program group with the name “MFC Tracer.”

  • If you have trouble setting breakpoints with the debugger, you can hard-code them into your application with the following statement:
    DebugBreak( );

    which is platform-independent. For MFC applications, you can also use:

    AfxDebugBreak( );

    This does an

    _asm int 3

    in Intel versions and calls DebugBreak on other platforms. The advantage (on Intel) is that you break in source code rather than in kernel code.

    Be sure to remove these statements when building release-mode applications or include them under #ifdef _DEBUG.

  • If you run into limitations with the Visual C++ debugger, you can always use TRACE statements and the TRACER application. Activating the Multiple application debugging option in TRACER can be very useful in tracking the order of events.

For additional information specific to MFC debugging, see the following topics:

  • Diagnostics

  • Debugging ActiveX Applications


Diagnostic Features

The Microsoft Foundation Class Library (MFC) contains many diagnostic features to help debug your application during development. These features, especially those that track memory allocations, will slow down your program. Others, such as assertion testing, will cause your program to halt when erroneous conditions are encountered.

In a retail product, slow performance and program interruption are clearly unacceptable. For this reason, MFC provides a method for turning the debugging and diagnostic features on or off. When you are developing your program, you typically build a Win32 Debug version of your program and link with the debug version of MFC. Once the program is completed and debugged, you build a Win32 Release version and link with the release version of MFC.

Note Before you can use many of the MFC diagnostic features, you must enable diagnostic tracing by setting the afxTraceEnabled flag and customizing the afxTraceFlags to the level of detail you would like to see in trace messages. The easiest way to make these settings is with the TRACER.EXE utility.

Open the Microsoft Visual C++ program group and double-click the MFC Tracer icon. For more information, see Technical Note 7.

Also see Knowledge Base article Q117326 “MFC Common Asserts, Causes, and Solutions.” Knowledge Base articles are available by connecting to:

http://www.microsoft.com/kb/

Choose a Microsoft product (Visual C++), enter the article ID (Q-number) and click Retrieve Article.

The following debugging features are included in all classes derived from CObject in the debug version of the MFC:

  • Trace Output You can trace debugging output to evaluate argument validity. See the topic The TRACE Macro.

  • Check program assumptions Use the ASSERT macro to check program assumptions. See the topic The ASSERT Macro.

  • Use the AssertValid Macro You can perform a run-time check of an object’s internal consistency. See the topic Using the ASSERT_VALID Macro.

  • Track Memory Allocations Use the DEBUG_NEW macro to show where objects were allocated. See the topic Tracking Memory Allocations.

  • Detect Memory Leaks You can use memory diagnostics to detect memory leaks. See the topic Detecting Memory Leaks.

  • Use Object Dumps You can use the dump member function to dump object contents. See the topics Dumping Object Contents, Dumping All Objects, and Interpreting an Object Dump.


The TRACE Macro

This topic explains how to use the TRACE macro during development to print or display debugging messages from a program. TRACE prints a string argument to your debugger.

Note With 32-bit MFC, the only way to get debug output is via the debugger.

The TRACE macro can handle a variable number of arguments, similar to the way printf operates. Following are examples of different ways to use TRACE macros:

int x = 1;
int y = 16;
float z = 32.0;
TRACE( "This is a TRACE statement\n" );

TRACE( "The value of x is %d\n", x );

TRACE( "x = %d and y = %d\n", x, y );

TRACE( "x = %d and y = %x and z = %f\n", x, y, z );

The TRACE macro is active only in the debug version of the class library. After a program has been debugged, you can build a release version to deactivate all TRACE calls in the program.

Tip When debugging Unicode, the TRACE0, TRACE1, TRACE2, and TRACE3 macros are easier to use because the _T macro is not needed.

For important information on the TRACE macro, see Diagnostic Services in the Class Library Reference and Technical Note 7.


The ASSERT Macro

This topic explains how to check assumptions made by your functions, using the ASSERT macro.

Note As of MFC version 4.0, MFC uses the same assertion mechanisms as the C Run-time Library. This means that the message format has changed somewhat.

For more information on the _ASSERT, _ASSERTE, _RPT, and _RPTF macros, see Using Macros for Verification and Reporting.

The most typical use of the ASSERT macro is to identify program errors during development. The argument given to ASSERT should be chosen so that it holds true only if the program is operating as intended. The macro evaluates the ASSERT argument and, if the argument expression is false (0), alerts the user and halts program execution. No action is taken if the argument is true (nonzero).

When an assertion fails, a message box appears with the following text:

assertion failed in file <name> in line <num>
Abort Retry Ignore

where <name> is the name of the source file and <num> is the line number of the assertion that failed.

If you choose Abort, program execution terminates. If you choose Ignore, program execution continues. It is possible to break into the debugger after an ASSERT by clicking Retry. Neither Abort nor Ignore will activate a debugger, so they provide no way to examine the call stack.

If you are running under the debugger and choose Retry, a call to AfxDebugBreak embedded in the code causes a break into the debugger. At this point, you can examine the call stack. To view the call stack, on the View menu, click Debug Windows and Call Stack. If you have enabled Just-in-time debugging, this will work even if the application is not being debugged.

The following example shows how the ASSERT macro could be used to check the validity of a function’s return value:

int x = SomeFunc(y);
ASSERT(x >= 0);   //  Assertion fails if x is negative

ASSERT can also be used in combination with the IsKindOf function to provide extra checking for function arguments, such as in the following example:

ASSERT( pObject1->IsKindOf( RUNTIME_CLASS( CPerson ) ) );

The liberal use of assertions throughout your programs can catch errors during development. A good rule of thumb is that you should write assertions for any assumptions you make. For example, if you assume that an argument is not NULL, use an assertion statement to check for that condition.

The ASSERT macro will catch program errors only when you are using the debug version of the Microsoft Foundation Class Library during development. It will be turned off (and produce no code) when you build your program with the release version of the library.

Note The expression argument to ASSERT will not be evaluated in the release version of your program. If you want the expression to be evaluated in both debug and release versions, use the VERIFY macro instead of ASSERT. In debug versions, VERIFY is the same as ASSERT. In release versions, VERIFY evaluates the expression argument but does not check the result.

See Also Using the ASSERT_VALID Macro


Using the ASSERT_VALID Macro

Use the ASSERT_VALID macro to perform a run-time check of an object’s internal consistency. The ASSERT_VALID macro is a more robust way of accomplishing

pObject->AssertValid();

Like the ASSERT macro, ASSERT_VALID is turned on in the debug version of your program, but turned off in the release version.


Overriding the AssertValid Function

The AssertValid member function is provided in CObject to allow run-time checks of an object’s internal state. AssertValid typically performs assertions on all the object’s member variables to see if they contain valid values. For example, AssertValid can check that all pointer member variables are not NULL. If the object is invalid, AssertValid halts the program.

Although you are not required to override AssertValid when you derive your class from CObject, you can make your class safer and more reliable by doing so. The following example shows how to declare the AssertValid function in the class declaration:

class CPerson : public CObject
{
protected:
    CString m_strName;
    float   m_salary;
public:
#ifdef _DEBUG
    virtual void AssertValid() const;    // Override
#endif
    // ...
};

When you override AssertValid, first call AssertValid for the base class. Then use the ASSERT macro to check the validity of the members unique to your derived class, as shown by the following example:

#ifdef _DEBUG
void CPerson::AssertValid() const
{
    // call inherited AssertValid first
    CObject::AssertValid();

    // check CPerson members...
    ASSERT( !m_strName.IsEmpty()); // Must have a name
    ASSERT( m_salary > 0 ); // Must have an income
}
#endif

If any of the member variables of your class store objects, you can use the ASSERT_VALID macro to test their internal validity (if their classes override AssertValid). The following example shows how this is done.

Consider a class CMyData, which stores a CObList in one of its member variables. The CObList variable, m_DataList, stores a collection of CPerson objects. An abbreviated declaration of CMyData looks like this:

class CMyData : public CObject
{
    // Constructor and other members ...
    protected:
        CObList* m_pDataList;
    // Other declarations ...
    public:
#ifdef _DEBUG
        virtual void AssertValid( ) const; // Override
#endif
    // Etc. ...
};

The AssertValid override in CMyData looks like this:

#ifdef _DEBUG
void CMyData::AssertValid( ) const
{
    // Call inherited AssertValid
    CObject::AssertValid( );
    // Check validity of CMyData members
    ASSERT_VALID( m_pDataList );
    // ...
}
#endif

CMyData uses the AssertValid mechanism to add validity tests for the objects stored in its data member to the validity test of the CMyData object itself. The overriding AssertValid of CMyData invokes the ASSERT_VALID macro for its own m_pDataList member variable.

The chain of validity testing might stop at this level, but in this case class CObList overrides AssertValid too, and the ASSERT_VALID macro causes it to be called. This override performs additional validity testing on the internal state of the list. If an assertion failure occurs, diagnostic messages are printed, and the program halts.

Thus, a validity test on a CMyData object leads to additional validity tests for the internal states of the stored CObList list object. With a little more work, the validity tests could include the CPerson objects stored in the list as well. You could derive a class CPersonList from CObList and override AssertValid. In the override, you would call CObject::AssertValid and then iterate through the list, calling AssertValid on each CPerson object stored in the list. The CPerson class shown at the beginning of this topic already overrides AssertValid.

This is a powerful mechanism when you build for debugging. When you subsequently build for release, the mechanism is turned off automatically.

Users of an AssertValid function of a given class should be aware of the limitations of this function. A triggered assertion indicates that the object is definitely bad and execution will halt. However, a lack of assertion only indicates that no problem was found, but the object isn’t guaranteed to be good.


Tracking Memory Allocations

The Microsoft Foundation Class Library (MFC) defines the macro DEBUG_NEW to assist you in locating memory leaks. You can use DEBUG_NEW everywhere in your program that you would ordinarily use the new operator.

Note As of MFC version 4.0, MFC uses the same debug heap and memory allocator as the C run-time library. For more information, see C Run-Time Debug Libraries.

When you compile a debug version of your program, DEBUG_NEW keeps track of the file name and line number for each object that it allocates. Then, when you call DumpAllObjectsSince, as described in the topic Dumping All Objects, each object allocated with DEBUG_NEW will be shown with the file and line number where it was allocated, thus allowing you to pinpoint the sources of memory leaks.

When you compile a release version of your program, DEBUG_NEW resolves to a simple new operation without the file name and line number information. Thus, you pay no speed penalty in the release version of your program.

To use DEBUG_NEW

  • Define a macro in your source files that replaces new with DEBUG_NEW, as shown here:
    #define new DEBUG_NEW

    Note While the framework uses DEBUG_NEW in debug builds, your code does not. You must enable this feature, as shown in this procedure.

    You can then use new for all heap allocations. The preprocessor will substitute DEBUG_NEW when compiling your code. In the Win32 Debug version of the library, DEBUG_NEW will create debugging information for each heap block. In the release version, DEBUG_NEW will resolve to a standard memory allocation without the extra debugging information.

See Also Detecting Memory Leaks


Detecting Memory Leaks

A memory leak occurs when you allocate memory on the heap and never deallocate that memory to make it available for reuse, or if you mistakenly use memory that has already been allocated. This is a particular problem for programs that are intended to run for extended periods. In a long-lived program, even a small incremental memory leak can compound itself; eventually all available memory resources are exhausted and the program crashes. Traditionally, memory leaks have been very hard to detect.

The Microsoft Foundation Class Library (MFC) provides classes and functions you can use to detect memory leaks during development. Basically, these functions take a snapshot of all memory blocks before and after a particular set of operations. You can use these results to determine if all memory blocks allocated during the operation have been deallocated.

The size or length of the operation you choose to bracket with these diagnostic functions is arbitrary. It can be as small as a single program statement, or it can span the entry and exit from the entire program. Either way, these functions allow you to detect memory leaks and identify which memory blocks have not been deallocated properly.

Note MFC automatically dumps all leaked objects when your program exits. As of MFC version 4.0, MFC uses the same debug heap and memory allocator as the C run-time library. For more information, see Memory Management and the Debug Heap.

This section covers the following topics:

  • Memory Diagnostics

  • Detecting A Memory Leak

  • Dumping Memory Statistics


Memory Diagnostics

Before you can use the memory diagnostics facilities, you must enable diagnostic tracing.

To enable or disable memory diagnostics

  • Call the global function AfxEnableMemoryTracking to enable or disable the diagnostic memory allocator. Because memory diagnostics are on by default in the debug library, you will typically use this function to temporarily turn them off, which increases program execution speed and reduces diagnostic output.

To select specific memory diagnostic features with afxMemDF

  • If you want more precise control over the memory diagnostic features, you can selectively turn individual memory diagnostic features on and off by setting the value of the MFC global variable afxMemDF. This variable can have the following values as specified by the enumerated type AfxMemDF:
    Value | Meaning
    allocMemDF | Turn on diagnostic memory allocator (default).
    delayFreeMemDF | Delay freeing memory when calling delete or free until program exits. This will cause your program to allocate the maximum possible amount of memory.
    checkAlwaysMemDF | Call AfxCheckMemory every time memory is allocated or freed.

    These values can be used in combination by performing a logical-OR operation, as shown here:

    afxMemDF | delayFreeMemDF | checkAlwaysMemDF;


Detecting a Memory Leak

The following instructions and example show you how to detect a memory leak.

To detect a memory leak

  1. Create a CMemoryState object and call the Checkpoint member function to get the initial snapshot of memory.

  2. After you perform the memory allocation and deallocation operations, create another CMemoryState object and call Checkpoint for that object to get a current snapshot of memory usage.

  3. Create a third CMemoryState object, call the Difference member function, and supply the previous two CMemoryState objects as arguments. The return value for the Difference function will be nonzero if there is any difference between the two specified memory states, indicating that some memory blocks have not been deallocated.

    The following example shows how to check for memory leaks:

    // Declare the variables needed
#ifdef _DEBUG
    CMemoryState oldMemState, newMemState, diffMemState;
    oldMemState.Checkpoint();
#endif

    // do your memory allocations and deallocations...
    CString s = "This is a frame variable";
    // the next object is a heap object
    CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );

#ifdef _DEBUG
    newMemState.Checkpoint();
    if( diffMemState.Difference( oldMemState, newMemState ) )
    {
        TRACE( "Memory leaked!\n" );
    }
#endif

    Notice that the memory-checking statements are bracketed by #ifdef _DEBUG / #endif blocks so that they are compiled only in Win32 Debug versions of your program.


Dumping Memory Statistics

The CMemoryState member function Difference determines the difference between two memory-state objects. It detects any objects that were not deallocated from the heap between the beginning and end memory-state snapshots.

To dump memory statistics

  • The following example (continuing the example from the previous topic) shows how to call DumpStatistics to get information about the objects that have not been deallocated:
    if( diffMemState.Difference( oldMemState, newMemState ) )
{
    TRACE( "Memory leaked!\n" );
    diffMemState.DumpStatistics();
}

    A sample dump from the example above is shown here:

    0 bytes in 0 Free Blocks
22 bytes in 1 Object Blocks
45 bytes in 4 Non-Object Blocks
Largest number used: 67 bytes
Total allocations: 67 bytes
    • The first line describes the number of blocks whose deallocation was delayed if afxMemDF was set to delayFreeMemDF. For a description of afxMemDF, see the procedure “To select specific memory diagnostic features with afxMemDF” presented under Memory Diagnostics.

    • The second line describes how many objects remain allocated on the heap.

    • The third line describes how many nonobject blocks (arrays or structures allocated with new) were allocated on the heap and not deallocated.

    • The fourth line gives the maximum memory used by your program at any one time.

    • The last line lists the total amount of memory used by your program.

For more information, see Dumping All Objects, Tracking Memory Allocations, AfxEnableMemoryTracking, and CMemoryState.


Using Object Dumps

Using Object Dumps covers the following topics:

  • Dumping Object Contents

  • Dumping All Objects

  • Interpreting an Object Dump


Dumping Object Contents

This topic explains how to get a diagnostic dump of the contents of your objects.

When deriving a class from CObject, you have the option to override the Dump member function and write a textual representation of the object’s member variables to a dump context which is similar to an I/O stream. Like an I/O stream, you can use the insertion (<<) operator to send data to a CDumpContext.

You do not have to override Dump when you derive a class from CObject. However, if you use other diagnostic features for debugging, providing the capability for dumping an object and viewing its contents is very helpful and highly recommended.

Note Before you can dump objects, you must enable diagnostic tracing so you can see the results of your dump in the debugger. For more information, see Diagnostics.

To override the Dump member function

  1. Call the base class version of Dump to dump the contents of a base class object.

  2. Write a textual description and value for each member variable of your derived class.

The declaration of the Dump function in the class declaration looks like:

class CPerson : public CObject
{
public:
#ifdef _DEBUG
    virtual void Dump( CDumpContext& dc ) const;
#endif

    CString m_firstName;
    CString m_lastName;
    // etc. ...
};

Note Since object dumping only makes sense when you are debugging your program, the declaration of the Dump function is bracketed with an #ifdef _DEBUG / #endif block.

In the following example from an implementation file for the class CPerson, the Dump function’s first statement calls the Dump member function for its base class. It then writes a short description of each member variable along with the member’s value to the diagnostic stream.

#ifdef _DEBUG
void CPerson::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CObject::Dump( dc );

    // now do the stuff for our specific class
    dc << "last name: " << m_lastName << "\n"
        << "first name: " << m_firstName << "\n";
}
#endif

Note Again, notice that the definition of the Dump function is bracketed by #ifdef _DEBUG / #endif directives. If you refer to afxDump in a program linked with the nondebug libraries, you will get unresolved externals errors at link time.

To send Dump output to afxDump

  • You must supply a CDumpContext argument to specify where the dump output will go when you call the Dump function for an object. MFC supplies a predefined CDumpContext object named afxDump that you will normally use for routine object dumping. The following example shows how to use afxDump:
    CPerson* pMyPerson = new CPerson;
// set some fields of the CPerson object...
//...
// now dump the contents
#ifdef _DEBUG
pMyPerson->Dump( afxDump );
#endif

    In Windows NT, afxDump output is sent to the debugger, if present. Otherwise, you won’t get any afxDump output.

    Note afxDump is defined only in the debug version of MFC.

For more information, see The TRACE Macro.


Dumping All Objects

This topic explains how to obtain a diagnostic dump of all objects in your program.

For information on dumping C run-time objects, see Using the Debug Heap and _CrtSetDbgFlag.

DumpAllObjectsSince dumps out a description of all objects detected on the heap that have not been deallocated. As the name implies, DumpAllObjectsSince dumps all objects allocated since the last Checkpoint. However, if no Checkpoint has taken place, all objects and nonobjects currently in memory are dumped.

Note Before you can use MFC object dumping, you must enable diagnostic tracing. See the Note in the topic Diagnostics.

To dump all objects

  • Expanding on the example shown in Detecting a Memory Leak in the topic Detecting Memory Leaks, the following code dumps all objects that have not been deallocated when a memory leak is detected:
    if( diffMemState.Difference( oldMemState, newMemState ) )
{
    TRACE( "Memory leaked!\n" );
    diffMemState.DumpAllObjectsSince();
}

    A sample dump from the preceding example is shown here:

    Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

{1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long

    The numbers in braces at the beginning of most lines specify the order in which the objects were allocated. The most recently allocated object appears first. You can use these ordering numbers to help identify allocated objects.

To set a breakpoint when a particular allocation occurs, first start your application in the debugger. Set the global variable _afxBreakAlloc to the number in braces discussed earlier. This will set a conditional breakpoint in your application that will trigger when the allocation you specify is being made. Looking at the call stack at this point will tell you the path your program took to get to the specified allocation.

The C run-time library has a similar function, _CrtSetBreakAlloc, that you can use for C run-time allocations.


Interpreting an Object Dump

The preceding dump comes from the memory checkpoint example introduced in Detecting a Memory Leak in the topic Detecting Memory Leaks. Remember that there were only two explicit allocations in that program — one on the frame and one on the heap:

// do your memory allocations and deallocations ...
CString s = "This is a frame variable";
// the next object is a heap object
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );

Start with the CPerson object; its constructor takes three arguments that are pointers to char. The constructor uses these arguments to initialize CString member variables for the CPerson class. In the memory dump, you can see the CPerson object listed along with three nonobject blocks (3, 4, and 5) that hold the characters for the CString member variables. These memory blocks will be deleted when the destructor for the CPerson object is invoked.

Block number 2 represents the CPerson object itself. After the CPerson address listing, the contents of the object are displayed. This is a result of DumpAllObjectsSince calling the Dump member function for the CPerson object.

You can guess that block number 1 is associated with the CString frame variable because of its sequence number and its size, which match the number of characters in the frame CString variable. The allocations associated with frame variables are automatically deallocated when the frame variable goes out of scope.

In general, you shouldn’t worry about heap objects associated with frame variables because they are automatically deallocated when the frame variables go out of scope. In fact, to avoid clutter in your memory diagnostic dumps, you should position your calls to Checkpoint so that they are outside the scope of frame variables. For example, place scope brackets around the previous allocation code, as shown here:

oldMemState.Checkpoint();
{
    // do your memory allocations and deallocations ...
    CString s = "This is a frame variable";
    // the next object is a heap object
    CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
}
newMemState.Checkpoint();

With the scope brackets in place, the memory dump for this example is as follows:

Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

Notice that some allocations are objects (such as CPerson) and some are nonobject allocations. “Nonobject allocations” are allocations for objects not derived from CObject or allocations of primitive C types such as char, int, or long. If the CObject-derived class allocates additional space, such as for internal buffers, those objects will show both object and nonobject allocations.

Notice that the memory block associated with the CString frame variable has been deallocated automatically and does not show up as a memory leak. The automatic deallocation associated with scoping rules takes care of most memory leaks associated with frame variables.

For objects allocated on the heap, however, you must explicitly delete the object to prevent a memory leak. To clean up the last memory leak in the previous example, you can delete the CPerson object allocated on the heap, as follows:

{
    // do your memory allocations and deallocations ...
    CString s = "This is a frame variable";
    // the next object is a heap object
    CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
    delete p;
}

For more information, see Detecting a Memory Leak and _CrtMemDumpAllObjectsSince.


How Can I View the Call Stack After an MFC Assert?

Full Problem Description: When debugging an application that uses the MFC library, an ASSERT gives the file and line number of its location, but I want to know how the code got to the assertion. How can I do this?

You need to examine the call stack. An ASSERT gives you three choices: Abort, Retry, or Ignore. Abort and Ignore do not activate the debugger, so there is no way to examine the call stack. If you choose Retry, the breakpoint (interrupt 3) embedded in your source code will cause a break and activate the debugger. The debugger will also be activated if you have enabled Just-in-time debugging. To examine the call stack, on the View menu, click Debug Windows and Call Stack.

Another way to catch an MFC assertion is by setting a breakpoint on the opening brace of the AfxAssertFailedLine function in AFXASERT.CPP. This source file is found in the MFC\SRC subdirectory of your Visual C++ installation directory.

The AfxAssertFailedLine function is called if an ASSERT fails. By setting a breakpoint on the opening brace of this function, the debugger will automatically come up when it finds an ASSERT in your code, or in the MFC library code. At this point, you can examine the call stack.

Remember that you cannot use the call stack to trace back through Windows messages.


How Can I Debug Access Violations When Running My Program Standalone?

Full Problem Description: My program runs fine in the Visual C++ environment, but when I run it standalone with Windows, it produces an access violation. How can I debug this problem?

Use Just-in-time debugging. If you set the Just-in-time debugging option before you compile, you can run your program standalone until the access violation occurs. Then, in the Access Violation dialog box, you can click Cancel to start the debugger.

Also see the Knowledge Base article Q133174, “How to Locate Where a General Protection (GP) Fault Occurs.” Knowledge Base articles are available by connecting to:

http://www.microsoft.com/kb/

Choose a Microsoft product (Visual C++), enter the article ID (Q-number) and click Retrieve Article.


How Can I Debug an Access Violation?

Full Problem Description: My program produces an access violation. How can I debug this?

Use the Call Stack window to work your way back up the call stack, looking for corrupted data being passed as a parameter to a function. If that fails, try setting a breakpoint at a point before the location where the access violation occurs. Check to see if data is good at that point. If so, try stepping your way toward the location where the access violation occurred.

If you can identify a single action, such as a menu command, that led to the access violation, you can try another technique: setting a breakpoint between the action (in this example, the menu command) and the access violation. You can then look at the state of your program during the moments leading up to the access violation.

You can use a combination of these techniques to work forward and backward until you have isolated the location where the access violation occurred. For more information, see Viewing the Call Stack for a Function.


How Can I Tell Which DLL My Program Crashed In?

Full Problem Description: My application crashes during a call to a system DLL or someone else’s code. I’m not sure which DLL was active when the crash occurred. How can I find out?

If you experience a crash in a DLL outside your own program, you can identify the location using the new Module List dialog box.

To find where a crash occurred using the Module List dialog box

  1. Note the address where the crash occurred.

  2. From the Debug menu, click Modules. The Module List dialog box appears.

    The Modules List dialog box has four columns: Module, Address, Path, and Order (which tells you the order in which modules are loaded). You may need to use the scroll bar to see the fourth column. There is a button at the top of each column. DLLs are initially sorted by load order.

  3. Click the Address button to sort the DLLs by address.

  4. Scan through the sorted list to find the DLL whose address range contains the address where the crash occurred.

  5. Note the DLL name and path for future reference.


How Can I Find Out If My Pointers are Corrupting a Memory Address?

Full Problem Description: I think that one of my pointers may be corrupting memory at address 0x00408000. How can I find out what is happening there?

Use the Memory window to view memory contents starting at that address. Set a breakpoint on that memory address. For more information, see View Memory Contents and Setting Breakpoints at a Memory Location Within the Current Scope.


How Can I Find Out Where My Pointer Is Getting Changed?

Full Problem Description: My pointer, ptr, should be pointing to a specific memory block, but it’s pointing somewhere else. How can I find out where it’s getting changed?

Set a data breakpoint on ptr. This breakpoint causes the program to halt when the address pointed to by ptr changes. If you set the breakpoint on *ptr instead, the breakpoint halts the program when data at the location pointed to by ptr changes. For more information, see Break when the location value of a pointer changes.


If Halted in MFC, How Can I Get Back to the Function That Called MFC?

Full Problem Description: When my program began drawing erratically, I used the Break command in the Debug menu to halt the program. Unfortunately, I ended up in MFC. I’m pretty sure the problem is in my code, not MFC. How can I get back to it?

Use the Call Stack window to navigate to the function from which MFC was called. For more information, see View the Call Stack for a Function.


How Can I Find Out Who Is Passing a Wrong Parameter Value?

Full Problem Description: I’ve discovered that the wrong parameter value is being passed to one of my functions. This function is called from all over the place. How can I find out who’s passing it the wrong value?

Using the Breakpoints dialog box, set a location breakpoint at the beginning of the function. Then click Condition, and use the Breakpoints Condition dialog box to enter an expression, such as Var==3, where Var is the name of the function being passed the bad value, and 3 is the bad value passed to it.

Now run the program again. The breakpoint causes the program to halt at the beginning of the function when Var has the value 3. You can then use the Call Stack window to find the calling function and navigate to its source code. For more information, see Setting Breakpoints and Viewing the Call Stack for a Function.


When Calling a Function Hundreds of Times, Which Call Failed?

Full Problem Description: My program fails on a call to a certain function, CnvtV. The program probably calls that function a couple hundred times before it fails. If I set a location breakpoint on CnvtV, the program stops on every call to that function, and I don’t want that. I don’t know what conditions cause the call to fail, so I can’t set a conditional breakpoint. What can I do?

You can set a conditional breakpoint without specifying a condition. Set the Skip Count field to a value so high that it will never be reached. In this case, since you believe the function CnvtV is called a couple hundred times, set Skip Count to 1000 or more. Then run the program and wait for it to fail. When it does, open the Breakpoints dialog box and look at the list of breakpoints. The breakpoint you set on CnvtV appears, followed by the skip count and number of iterations remaining:

at “CnvtV(ParamList)” skip 1000 times (750 remaining)

You now know that the breakpoint was skipped 250 times before the function failed. If you reset the breakpoint with a skip count of 250 and run the program again, the program stops at the call to CnvtV that caused it to fail last time. For more information, see Setting Breakpoints.


How Can I Debug an Active Process?

You can debug any active Windows 95 or Windows NT system process by attaching it to Visual C++. This functionality is critical in order to debug Windows NT services.

Warning You should not attach to a process unless you know what the process is and understand the consequences of attaching to and possibly killing that process. For example, if you attach to the WinLogon process and then stop debugging, the system will halt because it cannot operate without WinLogon.

To attach an active process

  1. From the Build menu, click Start Debug and Attach to Process.

    The Attach to Process dialog appears.

  2. Select the process you want to debug.

  3. Click OK.

When Visual C++ is loaded, look for statements in the status bar at the bottom of the screen stating that symbols for the application and its DLLs have been loaded. Then from the Debug menu, click Break to see the assembler listing in the main window. To view the call stack, on the View menu, click Debug Windows and Call Stack . Then double-click one of your functions. This brings up the source code for the source module in which a breakpoint can be set, or you can simply open a source file and set a breakpoint.

When you stop debugging the application, the application will be terminated. This is expected behavior.

If you pass an invalid PID, you will receive an error like:

   Invalid Parameter (Win32, Error 87)


Where Can I Look Up Win32 Error Codes?

WINERROR.H in the INCLUDE directory of your default system installation contains the error code definitions for the Win32 API functions. For an overview of error codes, see “Error Handling” in the ActiveX Programmer’s Reference in the Win32 SDK or Raising Software Exceptions.


Can I Debug an .EXE Without a Project or Workspace?

Yes, you can debug an .EXE without a project or workspace. For example, maybe you just picked up an .EXE and the related source code but you don’t have an associated project or workspace. You can use the Open command on the File menu to select the .EXE file you want to debug. The debug information should already be in either the .EXE or the related .PDB file. After Visual C++ opens the file, choose the Start Debug command on the Build menu to begin debugging.

Note You can also select the .EXE file you want to debug using the Open Workspace command on the File menu. Both the Open and the Open Workspace command work the same way.

Note When you open a file, the Executable for debug session edit box on the Debug tab of the Project Settings dialog is automatically set to the name of the .EXE file that is opened. When you close the temporary workspace, you can optionally save the project settings in a <project>.opt file.


Can I Debug a .DLL Without a Project or Workspace?

Yes, you can debug a .DLL without a project or workspace. For example, maybe you just picked up a .DLL and the related source code but you don’t have an associated project or workspace. You can use the Open command on the File menu to select the .DLL file you want to debug. The debug information should already be in either the .DLL or the related .PDB file. After Visual C++ opens the file, choose the Start Debug command on the Build menu to begin debugging.

Note You can also select the .DLL file you want to debug using the Open Workspace command on the File menu. Both the Open and the Open Workspace command work the same way.

Note When you open a file, the Executable for debug session edit box on the Debug tab of the Project Settings dialog is automatically set to the name of the file that is opened. You must specify the name of the .EXE file to use with this .DLL. When you close the temporary workspace, you can optionally save the project settings in a <project>.opt file.


How Can I Keep Focus When Stepping Through My Program?

Full Problem Description: My program has a window-activation problem. Stepping through the program with the debugger interferes with my ability to reproduce the problem, because my program keeps losing focus. Is there any way to avoid this?

If you have a second computer, use remote debugging. You can operate your program on the remote computer while you run the debugger on the host. For more information, see Debugging Remote Applications.


How Can I Use Debugger Windows While Debugging a Foreground Program?

Full Problem Description: I’m trying to debug a screen painting problem. To observe this problem, I have to keep my program in the foreground, which means I don’t have access to the debugging windows. What can I do?

If you have a second computer, you can use remote debugging. With a two-computer setup, you can watch the screen painting on the remote computer while you operate the debugger on the host.


Debugging SQL

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Visual C++ Enterprise Edition provides an integrated debugging process that can help find and fix errors in SQL Server stored procedures. Debugging SQL source is the process of finding and correcting SQL syntax errors so that your application can run smoothly and work as expected.

Note You can easily create and modify databases and SQL queries using the Visual Database Tools. For more information, see Visual Database Tools.

This section covers the following topics:

  • About SQL Debugging

  • Installing the SQL Debugger

  • Using the SQL Debugging Interface

  • Using Breakpoints with SQL Source

  • Controlling SQL Execution

  • Viewing and Modifying SQL Variables

  • Controlling the Call Stack Window

  • SQL Debugging Example: “Hello, World”

  • SQL Debugging Problems and Solutions

  • Debugging Extended Stored Procedures


About SQL Debugging

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

This section covers the following topics:

The SQL Debugging Process

SQL Debugging Limitations

How SQL Debugging Works


The SQL Debugging Process

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Using the debugger, you can control the execution of your SQL statement and examine the statement at selected points through multiple windows and dialog boxes. You can set breakpoints to halt execution at critical locations.

When running SQL source code with the debugger, you can single-step to observe the effects of your code. You can choose to enter the SQL code using the Step Into command, or step out using the Step Out command. Using the Step Over command, you can step past the SQL source code or stored procedure. You can even step into nested stored procedures. The Step Out command enables you to exit the SQL source code and return to the client program.

When you end a debugging session, the project retains any breakpoints you have set. When you reopen the project, the debugger restores the breakpoints in the proper locations. When the program is halted at a breakpoint, you can use the debug windows and dialog boxes to examine the state of your program.


SQL Debugging Limitations

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The SQL source code debugger provides many common debugging features. However, some debugger behaviors are not available for SQL debugging. The SQL debugger does not:

  • Debug single SQL statements executed outside of a stored procedure.

  • Support complex breakpoints. Only the location breakpoint is supported.

  • Provide debugging without a Data View. SQL debugging occurs only when a Data View is present in the current workspace. Without an active Data View, there is no debugging.

  • Use SQL memory windows. The memory window is only for the native application. You cannot view what might be thought of as SQL memory.

  • Debug extended stored procedures. Extended stored procedures are actually DLLs that are written in C++ (or any other language) and are not SQL-based.

  • Display registers. The SQL language is interpreted, so there are no registers.

  • Automatically modify cached values. You cannot always expect that changes to locals or parameters that are cached by the SQL interpreter will take effect during the time frame that you’re stepping through an SQL statement. Although you may have modified the value, it may never be checked again. You cannot force a refresh of cached values. Cached values exist because the SQL Server execution plan determines that the values for some variables will not be dynamically loaded for each statement execution or reference. For more information, see "SHOWPLAN Output" in the SQL Server Books Online.

  • Allow realtime modification of stored procedures. During SQL debugging, do not modify a stored procedure. Modification of a stored procedure may produce unpredictable results.


How SQL Debugging Works

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The SQL Server side has three primary SQL debugging components: AUTPRX32.DLL, AUTMGR32.EXE, and SDI50.DLL. They all must be on the path for the environment that the server is running in. The client side has two primary components: AUTMGR32.EXE and AUTPRX32.DLL.

When the client application begins making SQL Server connections through ODBC and DBLib, tracing turns on at the SQL Server side via a system level call or stored procedure. Once tracing begins, the SDI50.DLL on the server side exposes SQL Server events. The automation manager (AUTMGR32.EXE) functions as a proxy for remote OLE by determining where the server is located and providing remote procedure calls.

Depending on how the application accesses the SQL Server, the debugging context is for either the client application or the SQL Server. For example, you begin debugging by stepping through a client application just as you would for a normal debugging session. If the application uses an ODBC call to a stored procedure, you can step to that line. As soon as the application makes a call to the SQL Server, you can step into the stored procedure. You have execution control over the SQL source until you either step completely through it or release it. Debugging then continues for the client application. For the remainder of the debugging session, the debugging context switches back and forth between the client application and the SQL Server.


Installing the SQL Debugger

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

This section covers the following topics:

  • SQL Debugging Components

  • Configuring SQL Server

  • Installing for SQL Debugging Using ISAPI DLLs or Filters


SQL Debugging Components

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The Visual C++ 6.0 Enterprise Edition setup program provides options for installing client-side and server-side SQL debugging components on x86 platforms. The SQL Server machine must have Microsoft SQL Server 6.5 and Service Pack 3 installed. The following table shows the components needed for SQL server debugging.

Software Location

Software | Install on | Install From
ODBC, DBLib drivers, and Remote Automation (latest versions) | Client workstation | Visual C++ 6.0 Enterprise Edition CD.
AUTPRX32.DLL and AUTMGR32.EXE 2.20.4045 or later | Client and server | Visual C++ 6.0 Enterprise Edition CD.
SQLSRV32.DLL version 2.65.213 or later | Client | Visual C++ 6.0 Enterprise Edition or SQL Service Pack 3. (The SQLSVR32.DLL version 3.00.0075 that ships with the ODBC SDK is not a production driver and is not compatible.)
SQLSERVR.EXE | Server | SQL Server Service Pack 3.
SDI60.DLL | Server | Visual C++ 6.0 Enterprise Edition.
NTWDBLIB.DLL version 6.50.203 or later (required for debugging DBLib applications) | Client | Visual C++ 6.0 Enterprise Edition.
NT 4.0 — or — NT 3.51 with Service Pack 5. | Server | Windows NT 4.0 CD for NT 4.0. Visual C++ 6.0 Enterprise Edition CD, \SP5a.NT\i386\SETUP.EXE, for NT Service Pack 5.


Configuring SQL Server

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

To use the SQL debugger, you must configure SQL Server according to the following instructions.

To configure your computer to run SQL Server as an NT Service

  1. From the Control Panel, choose the Services application.

    The Services dialog box appears.

  2. In the list box, select MSSQLServer.

  3. Click Startup.

    The Service dialog box appears.

  4. Click This Account.

  5. In the This Account edit box, enter the logon user account of the person who will be using the SQL debugger. For example, type Domain1\MarkD.

  6. In the Password and Confirm Password edit boxes, enter the user’s password.

Note You must change and confirm the password in the Service dialog box if the user’s NT password changes.

  7. Click OK.

  8. Click Close.

    The SQL Server is now configured as an NT Service.

Note The SQL Server is incorrectly configured if SQL debugging fails and the event log contains the entry, “SQL Server when started as service must not log on as System Account. Reset to logon as user account using Control Panel.”


Installing for SQL Debugging Using ISAPI DLLs or Filters

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The default installations of Windows NT, Visual C++ 6.0 Enterprise Edition, and Internet Information Server (IIS) do not allow SQL debugging using ISAPI DLLs or ISAPI filters. Before you can start a debugging session that uses ISAPI DLLs or filters, you must specify whether IIS will allow anonymous logins.

This topic assumes that you already know how to use Microsoft Visual C++ version Enterprise Edition to debug ISAPI DLLs and filters. For more information on debugging internet extension DLLs and the Internet Server API, see ISAPI: Debugging.

This section provides important information about:

  • Controlling anonymous logins during debugging

  • Required software components and installation locations

  • Running multiple instances of INETINFO.EXE

  • Other important tips


Controlling Anonymous Logins During Debugging

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

You have to decide whether the Internet Information Server (IIS) will allow anonymous logins onto the computer that is running Visual C++ Enterprise Edition and IIS. You can set this with the Allow Anonymous checkbox on the Services Properties dialog box. The WWW service must be running before you can change its properties, but the properties are persistent across stopping and starting the WWW service. The WWW service, IIS, and INETINFO.EXE are equivalent. For more information, see the topic “Controlling Anonymous Access” in the Internet Information Server documentation.

To access the Service Properties dialog box

  1. Run the Internet Service Manager from the IIS program group.

  2. Select the WWW service.

  3. Click the right mouse button to bring up the shortcut menu, and then click Properties/Service Properties.

If you want the IIS to allow both anonymous logins and debugging ISAPI DLLs or filters, then you must add the IUSR_xxx account to the Administrators group using the User Manager program in the Administrative Tools group (xxx is the name of the NT machine on which IIS was installed). The IUSR_xxx account is automatically created when you install IIS. If anonymous logins are allowed, IIS uses the IUSR_xxx account when connecting to SQL Server.

If you disallow anonymous logins, there are no extra options required to do SQL debugging because the IUSR_xxx account is used only for anonymous logins. If you disallow anonymous logins, then SQL Server uses the user account of the person that is running both Visual C++ Enterprise Edition and IIS.


Required Software Components and Installation Locations

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The following four components are involved in using Visual C++ Enterprise Edition to debug ISAPI DLLs and filters:

  • Web browser for accessing the IIS server to be debugged.

  • Microsoft's Internet Information Server (either full IIS for NT Server or Peer Web for NT Workstation)

  • Microsoft Visual C++ Enterprise Edition

  • SQL Server 6.5.

The web browser can run on any computer and does not require any special setup options.

You must run the Visual C++ debugger on the same computer that is running IIS in order to debug the ISAPI DLLs and filters and SQL source. This is because you must use the Visual C++ debugger to debug the INETINFO.EXE. That is, you cannot run the debugger and the IIS on different computers.

You must also configure SQL Server as an NT service.


Running Multiple Instances of INETINFO.EXE

You must stop the WWW, FTP, and Gopher services before debugging INETINFO.EXE, otherwise there will be two instances of INETINFO.EXE running at the same time. Because the one running as a service takes priority, the debugger will not see the web requests and debugging will not work.


Other Important Tips

The ODBC Data Source Must Be a System DSN

The ODBC data source that ISAPI uses must be a system DSN, although Visual C++ Enterprise Edition will work with either a user or a system DSN.

Additional User Rights are Required to Successfully Host a Debugging Session

To successfully host a debugging session that requires both Visual C++ and IIS, the user id that you use to log onto Windows NT must have the following two user rights:

  • Act as part of the operating system.

  • Generate security audits.

To set the user rights

  1. Run the User Manager from the Administrative Tools program group.

  2. From the Policies menu, select User Rights.

  3. Select the Show Advanced User Rights checkbox.

  4. Add the user id to the Rights: "Act as part of the operating system" and "Generate security audits."


Using the SQL Debugging Interface

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

This section covers the following topics:

  • SQL Debugging Menu Items

  • SQL Debugging Windows

  • SQL Shortcut Menus

  • SQL Dialog Boxes

  • Spreadsheet Fields


SQL Debugging Menu Items

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Commands for SQL debugging are on the Debug menu, the Build menu, the View menu, and the Edit menu.

The Debug menu appears in the menu bar while the debugger is running (even if it is stopped at a breakpoint). From the Debug menu, you can control program execution and access the QuickWatch window.

When the debugger is not running, the Build menu replaces the Debug menu. The Build menu has a command called Start Debug, which lists a subset of the commands on the full Debug menu. These commands start debugging (Go, Step Into, and Run To Cursor). For a description of the Debug menu commands and the Debug commands on the Build menu, see Controlling SQL Execution.

The View menu contains the Debug Windows command with commands that display the various debugger windows, such as the Variables window and the Memory window. For more information about the debugger windows, see Viewing and Modifying SQL Variables.

From the Edit menu, you can access the Breakpoints dialog box, from which you can insert, remove, enable, or disable different types of breakpoints. For details, see Using Breakpoints with SQL Source.

A shortcut menu appears when you click the right mouse button in a debugger window. This menu lists commonly used commands applicable to that window.


SQL Debugging Windows

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Several specialized windows display debugging information. While debugging, you can access these windows using the Debug Windows command on the View menu. While you can copy information from any debugger window, you can print information only from the Output window.

The following table describes the information displayed in the debugging windows.

SQL Debugging Windows

Window | Displays
Output | Information about SQL results, as well as output from execution.
Watch | Names and values of variables.
Variables | Information about variables used in the current and previous statements.
Call Stack | Stack of all stored procedure calls that have not returned.

Debugging windows can be docked or floating. When a window is in floating mode, you can resize or minimize it to increase the visibility of other windows. For information on docked and floating windows, see Working with Docking Tool Windows.

Tip To set formatting and other options for these windows, use the Debug tab in the Options dialog box (accessed from the Tools menu).


SQL Shortcut Menus

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Each debugging window has a shortcut menu that lists frequently used commands for that window.

To display the shortcut menu for a window

  • Click the right mouse button inside the window.


SQL Dialog Boxes

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

In addition to windows, the debugger uses a number of dialog boxes to control breakpoints, variables, threads, and exceptions.

Tip To open the Breakpoints dialog box, use the Breakpoints command on the Edit menu. Use commands from the Debug menu to open the other debugger dialog boxes.

The following table describes the information displayed in the SQL debugging dialog boxes.

SQL Debugging Dialog Boxes

Dialog box | Displays
Breakpoints | All breakpoints assigned to your project. Use the Location tab in the Breakpoints dialog box to create new breakpoints. You must specify breakpoints by line number or stored procedure name. Do not use data or message breakpoints.
Exceptions | Any exceptions that occur. These exceptions are related to the client application and do not refer to the execution of the SQL Server or SQL source.
QuickWatch | Variables only. Use QuickWatch to quickly view locals or global variables, modify local variables, or add variables to the Watch window.
Threads | Threads related to either the client application or the SQL code. SQL debugging provides a thread that allows you to switch between the SQL code you’re debugging and threads in the client application.


Spreadsheet Fields

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The SQL debugger interface uses spreadsheet fields, similar to those of Microsoft Excel. These spreadsheet fields appear in the Watch window, the Variables window, and the QuickWatch dialog box.

Each window has certain spreadsheet fields that can be edited. In the Variables window, you can edit the fields in the Value column for local variables. In the Watch window, you can edit the fields in the Name and Value columns for local variables; global variables cannot be edited.

When working with these fields, you can autosize a column to fit its contents by double-clicking the divider. You can size a column manually by dragging the divider at the right edge of the column.

Note Rows cannot be resized because they adjust to fit the current font. To change the font size, open the Tools menu, click Options, and use the Format tab.

To select a spreadsheet field for editing

  1. Click one of the tabs to select the spreadsheet.

  2. Use the UP ARROW and DOWN ARROW keys to move to the correct line.

  3. Press TAB to select the field and advance the selection to the next editable field. Press SHIFT+TAB to deselect the current field and move the selection back to the previous editable field.


Controlling SQL Execution

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

This section covers the following topics:

  • About Controlling SQL Execution

  • Running to a Location

  • Stepping Into SQL Source

  • Stepping Over or Out of SQL Source

  • Interrupting Execution of SQL Source


About Controlling SQL Execution

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

To control SQL source code execution, click the Go, Step Into, or Run To Cursor command under Start Debug on the Build menu. The following table lists the Start Debug commands and their actions.

Build Menu Debug Commands

Build menu command | Action
Debug | Displays the initial debug commands: Go, Step Into, Run to Cursor.
Go | Executes code from the current statement until a breakpoint is reached or the end of the program is reached. This is equivalent to the Go button on the toolbar.
Step Into | Single-steps through statements in the SQL source code.
Run to Cursor | Executes the program as far as the line that contains the insertion point. This is equivalent to setting a temporary breakpoint at the insertion point location.

After you click Go, Step Into, or Run to Cursor, the Debug menu appears, replacing the Build menu on the menu bar. You can then control program execution using the commands listed in the following table.

Debug Menu Commands That Control SQL Execution

Debug menu command | Action
Go | Executes code from the current statement until a breakpoint is reached, the end of the program is reached, or an exception occurs. When the Debug menu is unavailable, you can click Go from the Start Debug submenu of the Build menu.
Restart | Resets execution to the first line of the application.
Stop Debugging | Terminates the debugging session and returns to a normal editing session.
Break | Halts the SQL source code or client application at its current location.
Step Into | Single-steps through statements in the SQL source. When the Debug menu is unavailable, you can click Step Into from the Start Debug submenu of the Build menu. If the SQL code is not encrypted, you can Step Into, Step Over, and Step Out.
Step Over | Single-steps through statements in the SQL source code.
Step Out | Executes the current SQL source code and returns to the next higher nesting level or currently executing client application instruction. Using this command, you can quickly finish executing the current SQL code. The maximum nesting level for SQL Server is 16.
Run to Cursor | Executes the SQL code up to the line that contains the insertion point. This command is equivalent to setting a temporary breakpoint at the insertion point location. When the Debug menu is unavailable, you can click Run To Cursor from the Start Debug submenu of the Build menu. Other debugging events, such as breakpoints, will clear the temporary breakpoint.


Running to a Location

To run until a breakpoint is reached

  • From the Debug menu, click Go.

To run to the cursor

  1. Open a source file, and move the insertion point to the location where you want the debugger to break.

  2. From the Debug menu, click Run To Cursor.

The Run To Cursor command also works in the Call Stack window and the Find box on the Standard toolbar.

Tip You can use the Run To Cursor command to return to an earlier stored procedure to retest your application, using different values for variables.


Stepping Into SQL Source

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Once your SQL code has stopped at a breakpoint, you can step through the statements one statement at a time using the Step Into command.

To run the program and execute the next statement (Step Into)

  1. While the SQL source is paused at a breakpoint, click Step Into from the Debug menu.

    The debugger executes the next statement, then pauses execution. If the next statement is a nested procedure, the debugger steps into that procedure and pauses execution at the beginning of the procedure.

  2. Repeat step 1 to continue executing the SQL code one statement at a time.

If you use this technique to step into a nested stored procedure, the debugger steps into the most deeply nested function. For example, assume the next line of code is:

EXEC return = stored_procedure param1, param2

The Step Into command causes the debugger to step into the called procedure stored_procedure and pause at the first line of execution.


Stepping Over or Out of SQL Source

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

You can step through your SQL source code one statement at a time by using the Step Over command. You can also exit from SQL code immediately and return to the client application by using the Step Out command.

To run the next statement in the SQL source

  1. Open an SQL source code file, and set a breakpoint.

  2. From the Debug menu, click Go.

    When the SQL code comes to the breakpoint, the debugger pauses.

  3. From the Debug menu, click Step Over.

    The debugger executes the next statement.

  4. Repeat step 3 to continue executing the program, one statement at a time.

To exit from SQL source code

  1. Set a breakpoint at the end of the SQL source code.

  2. From the Debug menu, click Go.

    The debugger executes to the end of the SQL code.


Interrupting Execution of SQL Source

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

There may be times, such as during an infinite loop, when you cannot set a breakpoint to halt the SQL source code. In such cases, you can interrupt your SQL code by clicking Break on the Debug menu. This action returns control to the client application.

Note Interrupting execution while Windows or other system code is running may produce unpredictable results.


Using Breakpoints with SQL Source

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

This section covers the following topics:

  • About Using Breakpoints with SQL Source

  • Quick Methods for Using Location Breakpoints with SQL Source

  • Using the Breakpoints Dialog Box


About Using Breakpoints with SQL Source

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Breakpoints tell the debugger where or when to break execution of SQL source code. You can set breakpoints in either the source window or the Call Stack window. A red dot identifies breakpoints in the source code.

When you halt the SQL code at a breakpoint, you can examine the state of your program, step through your code, and evaluate variables using the debugger windows.

The Breakpoints dialog box displays a list of all breakpoints set in the project. Use the Location tab on this dialog box to set, remove, disable, and enable SQL source breakpoints.

Note The SQL debugger only supports location breakpoints.

When you close a project, the debugger saves all breakpoints you have set as part of the project information. The next time you open the project, the breakpoints remain as you left them.

The debugger also provides quick methods for setting location breakpoints without using the Breakpoints dialog box.


Quick Methods for Using Location Breakpoints with SQL Source

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

With the SQL debugger, you can set location breakpoints:

  • On a specific statement in SQL source code.

  • At the beginning or the return point of a nested stored procedure.

You can disable and enable breakpoints on a statement line or in the Call Stack window. You can set or remove any breakpoint by using either the Breakpoints dialog box or the following quick procedures.

To set a breakpoint at a statement or the Call Stack window

  1. In a source window, move the insertion point to the statement where you want the program to break.

  2. Click the Insert/Remove Breakpoint toolbar button.

    A red dot appears in the left margin, indicating the breakpoint is set.

    Note If you want to set a breakpoint on a statement extending across two or more lines, you must set the breakpoint on the first line of the statement.

To set a breakpoint at the beginning of a stored procedure

  1. In the Find box on the Standard toolbar, type the stored procedure name.

  2. Click the Insert/Remove Breakpoint toolbar button.

    A red dot appears in the left margin at the beginning of the stored procedure, indicating that the breakpoint is set.

To disable a breakpoint

  1. In a source window, or in the Call Stack window, move the insertion point to the line containing the breakpoint you want to disable.

  2. Click the Enable/Disable Breakpoint toolbar button.

    The red dot in the left margin changes to a hollow circle.

To disable all breakpoints

  • Click the Disable All Breakpoints toolbar button.

    The red dots in the left margin change to hollow circles.

To enable a breakpoint

  1. In a source window, or in the Call Stack window, move the insertion point to the line containing the breakpoint you want to enable.

  2. Click the Enable/Disable Breakpoint toolbar button.

    The hollow circle in the left margin changes to a red dot.

Note If you set more than one breakpoint on a line, and some breakpoints are disabled while others are enabled, a gray dot appears in the left margin to indicate multiple breakpoints with varying status. The first time you click the Enable/Disable Breakpoint toolbar button with the insertion point on that line, all breakpoints on the line become disabled, and the gray dot changes to a hollow circle. If you click the Enable/Disable Breakpoint button again, all breakpoints on the line become enabled, and the hollow circle changes to a red dot.

To remove a breakpoint using the Breakpoints dialog box

  1. In the Breakpoints dialog box, select a breakpoint in the Breakpoints list.

  2. Click Remove.

    The red dot in the left margin disappears.

To remove a breakpoint in a window

  1. In the source window or the Call Stack window, move the insertion point to the line containing the breakpoint you want to remove.

  2. Click the Insert/Remove Breakpoint toolbar button.

    The red dot in the left margin disappears.

Note If a line contains enabled and disabled breakpoints, the Insert/Remove Breakpoint button removes all enabled breakpoints. Disabled breakpoints are not affected.


Using the Breakpoints Dialog Box

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The Breakpoints dialog box contains three tabs, but the Location tab is the only one you can use with the SQL debugger. Location breakpoints are set at a specific line of the SQL code or at the start of the SQL code. They break execution of the program when the location counter reaches the specified point in the SQL source code. You can set, remove, disable, enable, or view location breakpoints using the Breakpoints dialog box.

All current location breakpoints appear in the Breakpoints list at the bottom of the Breakpoints dialog box.


The Location Breakpoints Tab

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

You can use the Location tab in the Breakpoints dialog box to set a location breakpoint:

  • On a specific statement in SQL source code.

  • At the start of SQL source code.

Note Except where noted, the following procedures work only within the context of the currently viewed SQL source.

To set a breakpoint at the current location

  1. From the Edit menu, click Breakpoints.

    The Breakpoints dialog box appears.

  2. Choose the Location tab.

  3. Click the drop-down arrow next to the Break At text box.

  4. From the menu that appears, select the current statement location.

  5. Click OK.

Note If you want to set a breakpoint on an SQL statement extending across two or more lines, you must set the breakpoint on the first line of the statement.

To set a breakpoint at another location

  1. In the Break At text box on the Location tab, type a source-code line number (if the current location is in a source file). For source locations, type a period immediately before the line number.

  2. Click OK.

To set a breakpoint at the beginning of the current stored procedure

  1. In the Location tab, click the drop-down menu next to the Break At box.

  2. From the menu, choose the current stored procedure name that appears.

  3. Click OK.

To set a breakpoint at the beginning of a stored procedure

  1. In the Location tab, type the stored procedure name directly into the Break At text box.

  2. Click OK.

Note To set a breakpoint by typing the stored procedure name, two conditions are necessary: the current window must be focused on SQL source code from the same server and database as the stored procedure receiving the breakpoint, and you must be currently debugging.

To edit a location breakpoint

  1. In the Location tab, select the location breakpoint in the Breakpoints list.

  2. Edit the location that appears in the Break At text box.

  3. Click OK.


The Breakpoints List

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The Breakpoints dialog box lists all breakpoints currently set in your SQL code. You can use this list to examine all breakpoints, to disable breakpoints, or to enable breakpoints that you previously disabled. You can also use the list to remove (delete) a breakpoint.

To view the list of current breakpoints

  1. From the Edit menu, click Breakpoints.

    The Breakpoints dialog box appears.

  2. Use the scroll bars to move up or down the Breakpoints list.

To disable a breakpoint

  1. In the Breakpoints dialog box, find the breakpoint in the Breakpoints list.

  2. Clear the check box corresponding to the breakpoint that you want to disable.

  3. Click OK.

    The red dot in the left margin changes to a hollow circle.

To enable a breakpoint

  1. In the Breakpoints dialog box, find the breakpoint in the Breakpoints list.

  2. Select the empty check box corresponding to the breakpoint that you want to enable.

  3. Click OK.

    The red dot in the left margin changes to a hollow circle.

Tip You can also use the SPACEBAR to toggle the state of a breakpoint in the Breakpoints list.

Note An asterisk (*) in the breakpoint check box indicates that the breakpoint is not supported on the current platform.

To remove a breakpoint

  1. In the Breakpoints dialog box, select one or more breakpoints in the Breakpoints list.

  2. Click Remove.

    – or –

    Press the DELETE key.

  3. Click OK.

When you select a breakpoint in the Breakpoints list, the breakpoint information automatically appears in the text box of the Location tab. You can edit the breakpoint using the procedures described for that tab.

For a location breakpoint, you can click Edit Code to navigate to the SQL code where the breakpoint is set.

To view the SQL code where a breakpoint is set

  1. In the Breakpoints list, select a breakpoint.

  2. Click Edit Code.

This action takes you to the SQL source code with the breakpoint.


Viewing and Modifying SQL Variables

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The SQL debugger provides several methods to view and modify the value of a variable.

This section covers the following topics:

  • Using the QuickWatch Window

  • Using the Watch Window

  • Using the Variables Window


Using the QuickWatch Window

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

You can use QuickWatch to quickly examine the value of SQL variables and parameters. You can also use QuickWatch to modify the value of a local variable or to add a variable to the Watch window. You cannot modify the value of a global.

The QuickWatch dialog box contains a text box, where you can type a variable name, and a spreadsheet field that displays the current value of the variable that you specified.

The Current Value spreadsheet field displays only one variable at a time. Typing a new variable in the text box and pressing ENTER replaces the previous variable. QuickWatch displays SQL code variable values in their native format.

To view the value of a variable using QuickWatch

  1. Wait for the debugger to stop at a breakpoint.

    – or –

    From the Debug menu click Break to halt the debugger.

  2. From the Debug menu, click QuickWatch.

    The QuickWatch dialog box appears.

  3. Type or paste the variable name into the Expression text box.

  4. Click Recalculate.

  5. Click Close.

Tip The Expression drop-down list box contains the most recently used QuickWatch variables.

To quickly view the value of a variable using QuickWatch

  1. When the debugger is stopped at a breakpoint, switch to a source window, and click the right mouse button on a variable (Var, for example).

  2. From the shortcut menu, click QuickWatch Var.

  3. Click Recalculate.

  4. Click Close.

When the program is paused at a breakpoint or between steps, you can change the value of any variable in your program. This gives you the flexibility to try out changes and see their results in real time or to recover from certain logic errors.

To modify the value of a variable using QuickWatch

  1. From the Debug menu, click QuickWatch.

  2. In the Expression text box, type the variable name.

  3. Click Recalculate.

  4. Use the TAB key to move to the value you want to modify.

  5. Type the new value, and then press ENTER.

  6. Click Close.

Note Modified cached values may not take effect while you’re stepping through the SQL statement. Although you may have modified the value, it may never be checked again. There is no way to force a refresh.

To add a QuickWatch variable to the Watch window

  1. Use any of the procedures described previously to view the variable in the QuickWatch window.

  2. Click Add Watch.


Using the Watch Window

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Use the Watch window to specify local or global variables that you want to watch while debugging your program. You can also use this window to modify the values of local variables, but not global variables.

The Watch window contains four tabs: Watch1, Watch2, Watch3, and Watch4—Each tab displays a user-specified list of variables in a spreadsheet field. You can group variables that you want to watch together onto the same tab. For example, you could put variables related to a specific window on one tab and variables related to a dialog box on another tab. You could watch the first tab while debugging the window and the second tab while debugging the dialog box.

To add a variable to the Watch window

  1. From the View menu, click Debug Windows and Watch.

    The Watch window appears.

  2. Choose a tab for the variable.

  3. Type, paste, or drag the variable name into the Name column on the tab.

  4. Press ENTER.

    The Watch window evaluates the variable immediately and displays the value or an error message. The Watch window displays values in their native SQL format.

Tip The Watch window does not display variable type information, but you can show variable type information by using the window’s property page.

To view type information for a variable

  1. In the Watch window, select the line containing the variable whose type you want to see.

  2. Click the right mouse button in the Watch window and click Properties from the shortcut menu.

    – or –

    From the View menu, click Properties.

To remove a variable from the Watch window

  1. In the Watch window, select the line containing the variable you want to remove.

  2. Press DELETE.

When the program is paused at a breakpoint or between steps, you can change the value of any local variable in your program. This gives you the flexibility to try out changes and see their results in real time, or to recover from certain logic errors.

To modify the value of a variable using the Watch window

  1. In the Watch window, double-click the value.

    – or –

    Use the TAB key to move the insertion point to the value you want to modify.

  2. Type the new value, and press ENTER.

Note You can’t modify image, text, or datetime data types. String variables (varchar) cannot be made longer.

Note Modified cached values may not take effect while you’re stepping through the SQL statement. Although you may have modified the value, it may never be checked again during the current debugging session. There is no way to force a refresh.


Using the Variables Window

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The Variables window provides quick access to variables that are important in the program’s current context.

The window includes three tabs:

  • The Auto tab displays variables used in the current statement and the previous statement. It also displays return values when you step over or out of a function.

  • The Locals tab displays the variables that are local to the current function.

  • The This tab displays the object pointed to by this. The this relates to the routine currently at the client-side debugger. It does not refer to the SQL Server.

Each tab contains a spreadsheet with fields for the variable name and value. The debugger automatically fills in these fields.

In addition to the tabs, the Variables window has a Context box on the toolbar. This box displays a list of the current Call Stack in a drop-down list box. You can select a context from this list to specify the current scope of the variables displayed.

Tip The Context box is part of a toolbar that you can hide using the right mouse button.

You can expand or collapse the displayed variables using the tree controls, but you cannot add variables to the Variables window. You can add variables in the Watch window.

When the program pauses at a breakpoint or between steps, you can change the value of any non-const local variable in your program. This gives you the flexibility to try out changes and see their results in real time or to recover from some logic error and continue.

Note Changes to local variables may not take effect while you’re stepping through the SQL statement. Although you may have modified the value, it may never be checked again. There is no way to force a refresh.

Tip The Variables window does not display variable type information, but you can show variable type information by using the window’s property page. Move the insertion point to a variable name in the Variables window, click the right mouse button, and then click Properties. The type, expression (variable), and value are displayed in the Program Variable Properties window.

To display the Variables window

  1. From the View menu, click Debug Windows and Variables.

    The Variables window appears.

  2. Choose the Auto tab or Locals tab, according to the type of variables you want to see.

To view type information for a variable

  1. In the Variables window, choose the Auto tab or Locals tab.

  2. Select the line containing the variable whose type you want to see.

  3. Click the right mouse button in the Variables window and click Properties from the shortcut menu.

    – or –

    From the View menu, click Properties.

Although you cannot delete variables from the Variables window, you can edit the values of local variables.

To modify the value of a variable

  1. In the Variables window, choose the Auto tab or Locals tab.

  2. Select the line containing the local variable you want to modify.

  3. Double-click the value, or use the TAB key to move the insertion point to the value you want to modify.

  4. Type the new value, and press ENTER.

Note You can modify only the following types of data: char, varchar, and integer data types. String variables (varchar) cannot be made longer.

Tip To change the value of strings, modify the individual characters.

Navigating From the Variables Window

You can navigate to SQL statements from the Context box in the Variables window. This box displays the SQL statements, if available, in a source window.

To navigate from the Variables window to SQL statements

  • Select the SQL source name from the Context drop-down list box in the Variables window toolbar. For example, select the name of a stored procedure.

This procedure changes only the view of the program displayed in the Variables window and other debugger windows. It does not change the next line of execution or the value stored in the program counter.


Controlling the Call Stack Window

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

While using the SQL debugger, the Call Stack window displays the stack of currently active SQL code calls. Calling SQL source code pushes it onto the stack. When the SQL code returns, it is popped off the stack.

In the Call Stack window, the currently executing SQL code is at the top of the stack and older SQL calls are below it. By default, the window also displays parameter types and values for each function call. You can display or hide parameter types and values using the Debug tab of the Options dialog box or the right mouse button shortcut menu.

The Call Stack window acts much like the native Call Stack window. You can navigate to contexts in SQL source code. The Locals window also updates appropriately. From the Call Stack window, you can navigate to SQL statements and display the SQL statements in a source window.

To change the Call Stack display

  1. From the Tools menu, click Options.

  2. Choose the Debug tab.

  3. Under Call Stack window, click Parameter Values or Parameter Types, according to the information you want to display.

    – or –

  • In the Call Stack window, click the right mouse button, and from the shortcut menu, click Parameter Values or Parameter Types to toggle the display of that information.

To display the Call Stack window

  • From the View menu, click Debug Windows and Call Stack.

To view the Call Stack for SQL code

  1. Place the insertion point in the function.

  2. From the Debug menu, click Run To Cursor to execute your SQL code to the location of the insertion point.

    The Locals tab of the Variables window is updated automatically to display the local variables for the stored procedure.

  3. From the View menu, click Debug Windows and Call Stack.

    The stack lists calls in the calling order, with the current SQL code (the most deeply nested) at the top.

To navigate from the Call Stack window to a stored procedure’s statements

  • Double-click the stored procedure’s name in the Call Stack window.

    – or –

    Select the stored procedure name, and press ENTER.

This procedure changes only the view of the program shown in the Variables window and other debugger windows; it does not change the next line of execution or the value stored in the program counter.


SQL Debugging Example: "Hello, World"

SQL Debugging Example: “Hello, World”

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

This example assumes the following:

  • SQL Server 6.5 is installed.

  • VC++ Enterprise Edition is installed with the SQL Server Debugging options.

  • You have added SQL Server to your ODBC data sources using the ODBC application’s ODBC SQL Server Setup dialog box.

To create the SQL Debugging example “Hello World”

  1. Start VC++ Enterprise Edition.

  2. Start the SQL Server.

  3. From the File menu, click New.

  4. Select the Projects tab.

  5. Choose a Database Project.

  6. Type the Project Name “HelloWorld”.

  7. Click Create new workspace.

  8. Click OK.

    The SQL Data Source dialog appears.

  9. Choose a data source that is a debugging-enabled SQL Server database.

    For example, if you have a default SQL Server setup on your local workstation, you can use the “pubs” database by clicking the Machine Data Source tab and selecting “pubs”.

  10. Click OK.

  11. At the SQL Server Login dialog box, enter a valid Login ID and Password.

    You can click Options to change to any of the available databases. If you have a default setup, for the “pubs” database you can use Login Id “sa” and leave the Password blank.

  12. Click OK.

  13. Select the database.

    In the Data View pane of the project workspace, expand the project and select the database. For example, select “pubs(servername)” where “servername” is the name of your SQL Server.

  14. From the Insert menu, click New Database Item.

    The Insert Database Item dialog appears.

  15. In the Database Item listbox, select Stored Procedure.

  16. Click OK.

    The prototype for the HelloWorld stored procedure appears in the SQL editor.

  17. Edit the HelloWorld stored procedure so it looks as follows:
    CREATE PROCEDURE HelloWorld AS
PRINT 'Hello, world!'
RETURN (0)
  18. From the File menu, click Save.

    The stored procedure named “HelloWorld” is saved in the Stored Procedures folder associated with the database.

  19. Right-click in the HelloWorld editor window and click Debug.

  20. Automation manager will start.

  21. When the yellow arrow appears (the instruction pointer), you're debugging your stored procedure. Press F5 to finish executing it.

  22. In the Results tab of the Output window, you'll see "Hello, world" displayed. You may need to scroll the window to see it.

    You have successfully debugged your first SQL stored procedure.


SQL Debugging Problems and Solutions

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

There are two important places to begin troubleshooting the SQL debugging process:

  • The Windows NT event log that contains messages for all activities on the computer.

  • The Application Log that is generated by MSDEVSDI on the Server machine has messages from the SDI50.DLL. Some of the more common SDI50.DLL messages are discussed below.

By default, SETUP installs the SQL Server to use both logs, but by using SQL Enterprise Manager or SQL SETUP, you can control whether SQL Server uses one or both of the logs.

This section covers the following topics and error messages:

  • Does SQL Debugging Work With Microsoft Transaction Server?

  • Is My Automation Manager Identity Configured Correctly?

  • The Automation Manager Starts But Does Not Shut Down

  • What Is Direct Database Debugging?

  • What If I Lose the Server Connection?

  • How Can I Step from a PowerBuilder Application Into a Stored Procedure?

  • Does SQL Debugging Work with DAO?

  • My Debugging SQL Server Was Disabled Because No User Is Logged On to NT 4.0

  • A Timeout Occurs While Debugging a Stored Procedure...

  • How Can I Tell If Ad-Hoc Updates to SQL Server System Catalogs Are Required?

  • What Should I Do If the SQL Debug Menu Command Is Disabled?

  • The SQL Server Fails to Accept a Value Change While SQL Debugging

  • Error: Breakpoints Disabled

  • Error: Syntax Error or Access Violation

  • Error: SQL Server when started as service must not log on as System Account

  • Error: Could not find appropriate protocol for SDI to Debugger Communication

  • Error: Attempt to initialize OLE library failed. Check for correct versions of OLE DLLs

  • Error: An unexpected error ( %1 ) occurred. Debugging will be turned off for connection %2, %3

  • Error: Cannot do SQL debugging with this version of SQL Server...

  • Error: Could get unexpected errors doing SQL debugging...

  • Error: Connect to DSNName!master already exists for dbo...


Does SQL Debugging Work With Microsoft Transaction Server?

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

You can perform SQL debugging through Microsoft Transaction Server Components. In this case, the component usually calls a stored procedure via ODBC or any other data access methodology. The component needs to be running locally on the debugging machine as an inproc server. If the component is running remotely on a different machine or as a local server, you will be unable to engage the SQL debugging components. You will also not be able to perform SQL debugging if the transaction is started on a different machine as part of the DTC functionality from SQL Server and Microsoft Transaction Server.

To do SQL debugging with Microsoft Transaction Server

  1. Load the client .EXE as the active project workspace in Visual C++. This is the client application that you have created.

  2. Use the Project/Build Settings dialog to add your inproc server DLL as an additional DLL.

  3. Set a breakpoint in each stored procedure that you wish to debug.

  4. Begin debugging.

You should hit the breakpoints in your stored procedures and should be able to debug them normally. If you have problems, check to see if you can debug the stored procedure directly (select the stored procedure and click Start Debug on the Build menu).

Also, make sure that Microsoft Transaction Server is functioning properly. See the Microsoft Transaction Server README for further installation steps.


What Is Direct Database Debugging?

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

You can debug a stored procedure directly. Direct database debugging is useful when the stored procedure is testable as a stand-alone procedure and you simply want to determine if the stored procedure works correctly.

Direct database debugging bypasses the need for a supporting ODBC application that calls the stored procedure. You can type in arguments before the stored procedure runs.

For more information on how to quickly prepare for direct database debugging, see Creating a Direct Database Project.

Note If your application is a long series of interactions between program code and stored procedure results, you should consider using the standard application SQL debugging process.

To do direct database debugging

  1. In the Data View pane, select a stored procedure.

  2. Click the right mouse button in the Data View pane.

    – or –

    Click the right mouse button in the source code window.

  3. Click Debug.

    The debugger pauses execution at the first statement.


Is My Automation Manager Identity Configured Correctly?

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

If you install SQL Server and then install Visual C++ Enterprise Edition (including the Visual C++ Enterprise server-side components) on the same computer, the automation manager's identity is registered as The interactive user. In this scenario, if you log off from this machine but keep SQL server running as a service, you will not be able to remote debug against this server. Registering the automation manager's identity as The interactive user requires that someone be logged onto the computer to remotely debug SQL.

When installed with a pre-existing SQL Server, the Visual C++ setup registers the automation manager as The interactive user, with the assumption that you'll want to do local SQL debugging. SQL debugging may not work if the automation manager's identity is registered as The launching User (the default) and SQL server and the automation manager are already running in the service environment.

To change the automation manager identity

  1. On the computer on which you installed SQL Server and then installed Visual C++ Enterprise Edition, run DCOMCNFG.EXE.

  2. On the Applications tab in the Applications listbox, select Remote Automation CLSID_StubMarshaler.

  3. Click Properties.

  4. On the Identity tab, select the appropriate user account.


The Automation Manager Starts But Does Not Shut Down

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Starting SQL Debugging automatically starts the automation manager to manage remote OLE objects. Automation manager displays the current number of connections and objects that are instantiated on the remote machine. When Visual C++ shut downs, it does not shut down automation manager because there isn't any method of querying automation manager to determine if another application might also be using it.

You can manually shut down automation manager when it indicates there are no connections left.


What If I Lose the Server Connection?

Feature Only in Enterprise Edition SQL source code debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

If the SQL Server against which you are debugging fails during an SQL debugging session, you can reestablish the connection to the database.

To reestablish the database server connection

  • From the View menu, click Refresh.


How Can I Step from a PowerBuilder Application into a Stored Procedure?

Feature Only in Enterprise Edition SQL stored procedure debugging is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

If you are using both Visual C++ Enterprise Edition and PowerBuilder for application development, you can step from PowerBuilder debugging into the stored procedure debugger as follows:

  1. Open the PowerBuilder generated *.EXE as a WorkSpace.

  2. Insert a datasource with the stored procedures that the application calls.

  3. Set breakpoints as needed.

  4. Press F5.


Does SQL Debugging Work With DAO?

Yes.


My Debugging SQL Server Was Disabled Because No User Is Logged On to NT 4.0

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

If SQL Server and Visual C++ Enterprise Edition are installed on the same machine, the Visual C++ setup will register remote automation to run as the currently logged on user. If no user is logged onto the server, then access through Remote Automation is disabled.

To re-enable remote automation

  1. Run the DCOMCNFG.EXE utility, which is shipped as part of Windows NT 4.0.

Note The DCOMCNFG.EXE application is in the \winnt\system32 folder as part of the Windows NT 4.0 installation.

  2. From the Applications list select Remote Automation CLSID_STubMarshaler.

  3. Click Properties.

  4. Choose the Identity tab.

  5. Choose the user account that will run Remote Automation. In most cases you should be able to use The launching user.


A Timeout Occurs While Debugging a Stored Procedure...

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Full Error Text: A Timeout Occurs While Debugging a Stored Procedure Called From an MFC Application.

The number of seconds for a query timeout is contained in the member variable m_dwQueryTimeout in CDatabase. This is set in the constructor to the following value from AFXDB.H.

#define DEFAULT_QUERY_TIMEOUT 15

The value of m_dwQueryTimeout is passed to the ODBC API SQLSetStmtOption in the function CDatabase::OnSetOptions.

To resolve the timeout problem, add a call to CDatabase::SetQueryTimeout before your call to CDatabase::ExecuteSQL. For example:

CDatabase db;
db.OpenEx("DSN=MyDSN;UID=sa");
#ifdef _DEBUG
db.SetQueryTimeout(0);   // 0 signifies no timeout
#endif
db.ExecuteSQL("{call mysp}");


How Can I Tell If Ad-Hoc Updates to SQL Server System Catalogs Are Required?

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Certain stored procedures that ship with Microsoft SQL Server directly modify the system catalogs. By default, SQL Server does not allow such ad-hoc updates to system catalogs. If you try to edit and save one of these stored procedures in a database that does not allow ad-hoc updates, the following may occur:

  • You edit a stored procedure such as sp_bindefault (that resides in the master database and performs ad-hoc updates to the system catalog). When you save the procedure, you receive the following error message: PROCEDURE: sp_bindefault 3700[Microsoft][ODBC SQL Server Driver][SQL Server] Ad-hoc updates to the system catalogs not enabled.

  • Visual C++ Enterprise Edition attempts to add the altered stored procedure you have edited. This operation fails, because the execution plan generated for this stored procedure will alter system catalogs, and by default, SQL Server prevents this.

    Because of the way Visual C++ updates the stored procedure, the database no longer contains this stored procedure; it has been deleted. You still have the text of the altered stored procedure, however, and can recover from this situation. You still have the local copy of the stored procedure, and after your system administrator alters the defaults on the database, you can save it.

Note Do not refresh from the database at this point.

To fix the problem so that you can edit the stored procedure and alter the system catalogue, your System Administrator must reconfigure the system catalogs. You can contact your database administrator and request that the database be reconfigured to allow ad-hoc updates of the system catalogs. The database administrator can change the default setting by running the following script:

sp_configure 'allow updates',1
go
reconfigure with override

or by running the following ad-hoc statements:

exec sp_configure 'allow updates',1
go
reconfigure with override

These statements permit ad-hoc modifications to stored procedures that alter system catalogs.

For more information, see “Error 259” in Chapter 25 “Handling Error Messages” of Part 8 “Troubleshooting” in Administrator’s Companion in the SQL Server online documentation.


What Should I Do If the SQL Debug Menu Command Is Disabled?

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

If the right-button menu item for Debug or Debug Stored Procedure is disabled when you expect it to be enabled, check the following:

  • A data source must be inserted into the project and Data View must be visible.

  • The language in which the stored procedure that you are debugging is written must be T-SQL. To determine the language:
    1. Place the mouse pointer over a stored procedure that is open in an edit window.

    2. Click the right mouse button.

    3. Click Properties.

      The language appears in the Language drop-down list box.

  • SQL Server Debugging must be enabled. To enable SQL debugging, check the SQL Server Debugging check box on the SQL tab of the Options dialog box. The Options dialog box is available from the Tools menu.

  • The remote connection must be set to Local, not to TCP/IP. To set the remote connection, click the Debugger Remote Connection command from the Build menu.

  • The project configuration must be Win32 Debug. To set the current project configuration, click Configurations on the Build menu.

  • The stored procedure must be stored on a SQL Server version 6.5 or later.


The SQL Server Fails to Accept a Value Change While SQL Debugging

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The SQL debugger's watch window will accept values greater than the variable's declared limit, but SQL server adheres to the size limit and truncates the value. For example, if you declare a variable as follows:

@name varchar(30)

and then use the watch window to change name to a value that is longer (such as 35 characters), the debugger will accept the value but truncate the extra five high-order characters.


Error: Breakpoints Disabled

If your workspace includes both a C++ and a database project, it is possible to encounter a message that warns of one or more break points being disabled when you begin debugging the database. This happens when you have C++ breakpoint set in your C++ project and you begin debugging the database project before the C++ project. In some cases, the debugger will not be able to find the C++ symbols. The workaround is to first begin debugging the C++ project, which allows the debugger to load the C++ symbols, before you debug the database project.


Error: Syntax Error or Access Violation

Full Error Text: Syntax error or access violation. State:37000,Native:7134,Origin:[Microsoft][ODBC SQL Server Driver]

The SQL Server Service Pack 2 (06.50.0240) that ships with the Visual C++ Enterprise Edition has a bug that may cause a failure in CRecordset::Edit mode during the call to CRecordset::Update.

Although previous versions of the ODBC driver turned these items ON by default, the ODBC driver that ships with this version of SQL Server now gives you the option to turn ON or OFF the following items:

  • Use ANSI Quoted Identifiers

  • Use ANSI Nulls, Padding, and Warnings

If you encounter this error and you have Use ANSI Nulls, Padding, and Warnings turned ON, try the following workaround:

  1. Open the ODBC Data Source Administrator using the icon in the Control Panel.

  2. Select your SQL Server Data Connection and click Configure.

  3. Click Options.

  4. Clear the Use ANSI Nulls, Padding and Warnings option


Error: SQL Server when started as service must not log on as System Account

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

The SQL Server is incorrectly configured if SQL debugging fails and the event log contains the entry “SQL Server when started as service must not log on as System Account. Reset to logon as user account using Control Panel”.

To set SQL Server to logon as user account

  1. From the Control Panel, double-click Services.

    The Services dialog appears.

  2. Select MSSQLServer and click Startup.

  3. Click This Account.

  4. Choose LocalSystem or use the browse button to locate other accounts.

  5. Enter the Password and Confirm Password.

  6. Click OK.

  7. Click Close.


Error: Could not find appropriate protocol for SDI to Debugger Communication

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Check supported network protocols and RPC support on the server machine and the machine on which Visual C++ Enterprise Edition is running. SDI tries to find a common protocol between these two computers.


Error: Attempt to initialize OLE library failed. Check for correct versions of OLE DLLs

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

If you are using Windows NT 3.51, install the Windows NT Service Pack 5. For more information, see SQL Debugging Components.


Error: An unexpected error ( %1 ) occurred. Debugging will be turned off for connection %2, %3

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Look at the error number and associated message that is supplied by the operating system.

  • %1 A hexadecimal error number that is supplied by the operating system.

  • %2 The SPID.

  • %3 An error message that is supplied by the operating system.


Error: Cannot do SQL debugging with this version of SQL Server...

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Full Error Text: Cannot do SQL debugging with this version of SQL Server. Require Service Pack 1 of version 6.50 of SQL Server.

You are using the released version of Microsoft SQL Server 6.5. Install the SQL Debugging Components from the Visual C++ Enterprise Edition. For more information, see SQL Debugging Components.


Error: Could get unexpected errors doing SQL debugging...

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Full Error Text: Could get unexpected errors doing SQL debugging SQL Server version 6.50 Service Pack 1 required.

You are using the released version of Microsoft SQL Server 6.5. Install the SQL Debugging Components from the Visual C++ Enterprise Edition. For more information, see SQL Debugging Components.


Error: Connect to DSNName!master already exists for dbo...

Feature Only in Enterprise Edition This feature is supported only in Visual C++ Enterprise Edition. For more information, see Visual C++ Editions.

Full Error Text: Connect to DSNName!master already exists for dbo. Additional connections as a different user not permitted.

If you receive this error message, a database name was not entered in the Database Name edit box of the ODBC SQL Server dialog box. The solution is to enter a database name into the ODBC SQL Server dialog box or the Login dialog box. Click Options to see the Database Name edit box.


Debugging Extended Stored Procedures

Caution You should not debug an extended stored procedure on a computer that is running as a production server.

To debug an extended stored procedure, you must have the following products installed:

  • SQL Server 6.5

  • Windows NT (server or workstation)

  • Visual C++

To debug an extended stored procedure

  1. Use Visual C++ to create a debug build of an extended stored procedure DLL.

  2. Stop SQL Server if it is currently running as a service. Open the Services tool in Control Panel, highlight MSSQLSERVER and click Stop.

  3. Copy the debug version of the DLL to the directory where sqlservr.exe resides or to any directory in the search path.

    Tip You can use the Post-build step tab in the Project Settings dialog box to copy the DLL. Type in a command to copy the dll, for example, Copy c:\MyProjects\MyXProc\debug\MyXProc.dll c:\mssql\binn.

  4. Register the extended stored procedure.

  5. Specify SQL Server as the calling executable and working directory for the extended stored procedure DLL. Modify the settings in the Debug tab of the Project Settings dialog box as follows:
    • If SQL Server was installed in the default location, type C:\MSSQL\BINN\SQLSERVR.EXE in the Executable for debug session box.

    • Set the Working directory entry to C:\MSSQL\BINN.

    • Set the Program arguments entry to -c. The -c option indicates to SQL Server that it is being started from the command line and not as a service. This will cause SQL Server to start up faster.

    This will start the SQL Server not as a service but as a console application under the control of the Visual C++ debugging environment. This will allow breakpoints to be properly trapped and handled.

  6. Set breakpoints in the source code of the extended stored procedure and begin the debugging session.

    A console window will appear as SQL Server starts. When text scrolling stops (the last messsage will say “Launched startup procedure 'sp_sqlregister'”), SQL Server will be started and ready to process requests.

  7. Execute the extended stored procedure. You can do this is one of three ways:
    • Start Visual C++ Enterprise Edition and create a database project with a data connection for the database that contains the extended stored procedure. Create an SQL script file that calls the extended stored procedure.

    • Call the extended stored procedure from your own application.

    • Use any application that allows you to call extended stored procedures. For example, ISQL/W (included with SQL Server) or ODBC Test (included with ODBC SDK).

    The VC++ debugger will break when a line containing a breakpoint is executed.

For specific tips on writing extended stored procedures, consult the SQL Server section of the Microsoft Knowledge Base.

See Also Debugging DLLs, Creating an Extended Stored Procedure.


Performance Tuning

This section of the documentation talks about tuning an application through code improvements and profiling.

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.
Overviews
How Do I
Details
What else do you want to do?
Enable profiling in the development environment.
Select code to profile.

Interesting home pages
Visual C++ Home The entire Visual C++ product.


Overviews: Performance Tuning

Home | How Do I | Details

What is presented here should give you the concepts to help you increase your application's performance.

Performance tuning means several questions and issues:

  • What part of your code has to be fast?

  • Know the size and speed of your code.

  • Know the cost of new features.

  • Know the minimum work needed to accomplish the job.

Visual C++ has several tools that you can use to measure performance:

  • PView (“process viewer”)

  • Profiler

  • Spy++

  • Windows NT Performance monitor

The Performance Tuning section covers the following topics:

  • Profiling

  • Tips for Improving Time-Critical Code


Profiling: Overview

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The profiler is an analysis tool that you can use to examine the run-time behavior of your programs. By using profiler information, you can determine which sections of your code are working efficiently. The profiler can produce information showing areas of code that are not being executed or that are taking a long time to execute.

Because profiling is a tuning process, you should use the profiler to make your programs run better, not to find bugs. Once your program is fairly stable, you should start profiling to see where your code could perform better.

Use the profiler to determine whether,

  • an algorithm is effective (timing),

  • a function is being called too many or too few times with respect to the problem domain (counting), or

  • a piece of code is being covered by software testing procedures (coverage).

The profiler can be run from within the development environment or from the command line.

  • Types of Profiling

  • Profiling Tips

  • Profiling from the Command Line

  • Profiling from the Development Environment

  • Spy++

  • PView


Types of Profiling

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The profiler can analyze the execution of your code with two levels of detail:

Function Profiling is good for detecting inefficient code. Function profiling is faster than line profiling because there is less information to collect.

Line Profiling can be useful for checking the validity of an algorithm because it shows how many times each line is executed in response to certain input data. Line profiling also lets you see which lines aren’t executed at all.


Function Profiling

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The profiler provides four ways to profile by function:

  • Function timing lists time spent in functions together with “hit count”—the number of times the function was called.

  • Function counting lists only hit counts, but it is faster than function timing.

  • Function coverage lists functions that are or are not executed.

  • Function attribution takes a snapshot of the stack on each function call.

Debugging information is not required for function timing, function counting, or function coverage. The profiler reads the project’s .MAP file to match addresses with function names. It also creates a modified executable module and saves it in a temporary file with an ._XE or ._LL extension. This modified file contains thunks (substitutions for function calls), enabling the profiler to count and time the functions.

Caution With function timing, function counting, or function coverage, the function calls go through thunks for the profiler to record all the relevant information, which requires modification of the stack of the original executable (.EXE) file. As a result, it is not possible to profile functions that modify the stack themselves.

For example, the function AfxDispatchCall in the Microsoft Foundation Class dynamic-link library (.DLL) cannot be profiled, because it modifies the stack. However, the rest of the application or the .DLL can be profiled by excluding the object module that contains this offending function. (PREP automatically excludes the object module that defines AfxDispatchCall, olecall.obj.) The module that contains the offending function can be identified using the .MAP file (see the Generate Mapfile linker option). For more information on how to exclude modules, see the /EXC option of PREP.


Function Timing

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Function Timing option in the Profile dialog box profiles the current project, recording how many times each function was called (hit count) as well as how much time was spent in each function and called functions.

Here is a sample of the data provided by function timing:

Func      Func+Child
Time   %   Time   %   Hit Count   Function
------------------------------------------------------------
2.606   48.1   2.606   48.1   2   _SetCursor@4

The Func Time column reports how much time it took for the function to run in seconds. The next column shows what percent of the total profile time is represented by the function time. Func+Child Time refers to the total time profiled for the function as well as any functions called by that function. The next column shows what percent of the total profile time is represented by the Func+Child time. The Hit Count column reports the number of times that the function was called. The Function column displays the decorated name of the function.

Function attribution is also available with function timing.


Function Counting

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Function Counting option in the Profile dialog box records how many times each function was called (hit count).

Function counting is similar to function timing, but only hit counts (greater than zero) are recorded, so profiled program execution is slightly faster. Here is a sample output line with column headings:

Hit Count   %   Function
------------------------------------------------------------
1   25.0   LoadCursorA@8(user32.def)

Function attribution is also available with function counting.


Function Coverage

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Function Coverage option in the Profile dialog box profiles the current project, recording whether a function was called.

Function coverage profiling is useful for determining which sections of your code are not being executed. The profiler lists all profiled functions, with an asterisk (*) marking those that were executed. The profiling overhead for function coverage matches the overhead for function counting. Here is a sample function coverage report:

Covered Function
------------------------------------------
    .    _InitInstance (generic.obj)
    .    _LoadAcceleratorsA@8 (user32.def)
    *    _LoadCursorA@8 (user32.def)
    .    _LoadIconA@8 (user32.def)
    .    _SendMessageA@16 (user32.def)
    *    _SetCursor@4 (user32.def)
    .    _SetDlgItemTextA@12 (user32.def)


Function Attribution

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Attribution data can be collected for function counting or function timing. Function attribution records information about who called a particular function by taking a snapshot of the stack on each function call. Function hits and function timing can then be attributed to particular stacks. You can specify the depth of the stack to profile with attribution. If the stack depth is set to one (1), only the immediate calling function will be recorded. You can also attribute function timing and hits for all functions in the entire caller history.

See the PREP switches /AT and /STACK for more information on function attribution.


Line Profiling

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

With the profiler’s two line profiling options, you can see which source lines are being executed.

  • Line counting shows you how many times each line was executed.

  • Line coverage shows you which lines were executed at least once.

Line profiling uses debugging information in your .EXE file to trigger the profiler, so it does not need a .MAP file.


Line Counting

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Line Counting option in the Profile dialog box records how many times each line was called (hit count). To start a line count profile, use a custom batch file that specifies the source module and the lines to profile.

Here is a sample of the output of a line counting profile run:

          Hit
  Line    count   %   Source
-----------------------------------------------------
    1:                // test.c
    2:
    3:                #include <windows.h>
    4:
    5:                void WasteTime(HANDLE hInstance, HWND hWnd)
    6:     1     0.0  {
    7:                     LONG lCount, lX;
    8:                     HCURSOR hOldCursor;
    9:     1     0.0       hOldCursor = SetCursor(LoadCursor(NULL,
                                     IDC_WAIT));
   10:     1     0.0       for(lCount = 0; lCount < 1000L;  lCount++)  {
   11:  1000    49.9               lX = 57L;
   12:  1000    49.9       }
   13:     1     0.0       SetCursor(hOldCursor);
   14:     1     0.0 }

Note All included source lines are printed, even if they are not executed.

Line counting profiling is very slow because the profiler inserts a debugging breakpoint for every source code line, and these breakpoints remain for the duration of the profile session. To speed up profiling, reduce the number of lines selected for profiling. For more information, see Select Code to Profile.


Line Coverage

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Line Coverage option in the Profile dialog box profiles the current project, recording whether a line was executed.

Line coverage profiling is useful for determining which sections of your code are not being executed. The profiler lists all profiled lines, with an asterisk (*) marking those that were executed. The profiling overhead for line coverage is lower than for line counting, because the profiler needs to stop at a line only once. Here is a sample line coverage report:

  Line Covered  Source
-----------------------------------------------------
    1:          // waste.c
    2:
    3:          #include <windows.h>
    4:
    5:          void WasteTime(HANDLE hInstance, HWND hWnd)
    6:    *     {
    7:              LONG lCount, lX;
    8:              HCURSOR hOldCursor;
    9:    *         hOldCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
   10:    *         for(lCount = 0; lCount < 1000L; lCount++) {
   11:    *             lX = 57L;
   12:    *         }
   13:    *         if(lCount == 0) {
   14:    .             lCount = 1; // should never execute
   15:              }
   16:    *         SetCursor(hOldCursor);
   17:    *     }

Note All included source lines are printed, even if they are not executed.

Line coverage profiling is much faster than line counting profiling because the profiler can remove the inserted breakpoints when those lines are first executed.


Profiling Tips

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This section discusses some guidelines for approaching your profiling task.

  • Don't profile your entire application. Profile only the specific areas of interest to you. See PREP Phase I commands /EXC and /INC. There are a lot of areas that don't make sense to profile. For example, you probably don’t care about performance in general user interface code.

  • Reported times will be inaccurate, so do an average of a few runs and keep accurate notes. The averages will be more precise. You can accumulate profiler statistics for multiple runs by merging (the Merge option).

  • To get more consistent results, reduce the number of processes running on your machine when you profile.

  • Disconnect any network connections to relieve the operating system of the need to service incoming packets.

  • If you are profiling with function timing and your timings and calculated overhead vary, you may want to use the /CB switch in PREP Phase I. Calculated overhead appears in default (not tab-delimited) PLIST format.

  • Analyze the report. If you have a function that is reportedly using a lot of time, see if the reported calls to profiled subroutines add up to roughly the amount of time the function is using.

  • Look at the hit counts. If you are iterating through an algorithm 1,000 times, are the functions it uses getting called the right number of times? Is there a way to reduce the calls? If a function isn't used, it doesn't cost anything.

  • Just because you have a tried and true function, don't discount it as a possible problem.

  • The times attributed to a function also include any children of the function.

  • Disk caching can result in faster subsequent profile runs.

  • Linked lists are slow; profiling shows this.

  • Long functions can be difficult to profile. In some cases you may want to wrap part of a function within a subroutine to check the timing of that chunk of code.

  • You can't profile threads. You can, however, use the /SF PREP (phase I) option to start profiling at the function that is the thread entry point. Or, to test a thread, make it a subroutine and create a special test case for it; this can be difficult to do.

For tips on how to improve your code to increase performance, see Tips for Improving Time-Critical Code.


Profiling from the Command Line

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

You would issue the appropriate PROFILE, PREP, and PLIST commands from the command line if you need to issue nondefault PROFILE, PREP Phase II, or PLIST commands.

For example, you can only do function counting and line counting from the command line. You can create a tab-delimited profiler report, and you can do more sophisticated merging from the command line.

You can place all your profiling commands in a batch file, which is more convenient than simply issuing profiler commands at the command line.

See Run the Profiler from the Command Line.


Profiling from the Development Environment

Home | How Do I | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The development environment provides the Profile dialog box (available from the Build menu) for access to profiler functionality. There are options to do line and function profiling, and to do multiple profiling runs.

If you need to use nondefault PROFILE, PREP Phase II, or PLIST commands, you can make a batch file and run that batch file either directly from the command line or via the Custom option in the Profile dialog box.

See Run the Profiler from the Development Environment.


Tips for Improving Time-Critical Code

Home | Overviews

Writing fast, time-critical code requires that you carefully analyze all aspects of your code and how it interacts with the system. This section will suggest alternatives to some of the more obvious coding techniques when fast execution times are required.

One of the key factors in writing fast code is to "know your code." If you are using a library, make sure you have the source code (or have a thorough understanding of how the library works where it pertains to performance-critical code) which will enable you to make informed decisions.

In addition to the suggestions provided in this section there are tools like the profiler and Windows NT performance monitor (perfmon.exe) that may assist you in analyzing and maximizing your code's performance.

This section offers suggestions to ensure that the time-critical portions of your code perform satisfactorily.

  • Cache Hits and Page Faults

  • Sorting and Searching

  • MFC and Class Libraries

  • Shared Libraries

  • Heaps

  • Threads

  • Small Working Set

Summary of Improving Time-Critical Sections of Code

The following points summarize where you should concentrate your efforts to make your code run as efficiently as possible:

  • Know which parts of your program have to be fast.

  • Know the size and speed of your code.

  • Know the cost of new features.

  • Know the minimum work needed to accomplish the job.

Cache Hits and Page Faults

Missed cache hits, on both the internal and external cache, as well as page faults (going to secondary storage for program instructions and data) slow the performance of a program.

It is estimated that a missed CPU cache hit results in a loss of 10–20 clock cycles. A missed external cache hit results in a loss of 20–40 clock cycles. A page fault results in about 1 million lost instructions. Therefore, it is in the best interest of program execution to write code that will reduce the number of missed cache hits and page faults.

One reason for slow programs is that they take more page faults or miss the cache more often than necessary. To avoid this, it’s important to use data structures with good locality of reference, which means keeping related things together. Sometimes a data structure which looks great turns out to be horrible because of poor locality of reference, and sometimes the reverse is true. Here are two examples:

  • Dynamically allocated linked lists can reduce program performance because when you search for an item or when you traverse a list to the end, each skipped link could miss the cache or cause a page fault. A list implementation based on simple arrays might actually be much faster because of better caching and fewer page faults—even allowing for the fact that the array would be harder to grow, it still might be faster.

  • Hash tables that use dynamically allocated linked lists can degrade performance. By extension, hash tables that use dynamically allocated linked lists to store their contents might perform substantially worse than you might expect. In fact, in the final analysis, a simple linear search through an array might actually be faster (depending on the circumstances). Array-based hash tables (so-called “closed hashing”) is an often-overlooked implementation which frequently has superior performance.

Sorting and Searching

Sorting is an inherently time consuming operation (compared to other typical operations you might have to do). The best way to speed up code that is slow due to sorting is to find a way to not sort at all.

  • Perhaps the sort can be deferred to a non-performance–critical time.

  • Perhaps only part of the data truly needs to be sorted.

  • Perhaps information was available at some other time that would have made the sort easier to do later.

You might be able to build the list in sorted order. But this might slow you down overall because inserting each new element in order could require a more complicated data structure with possibly worse locality of reference. There are no easy answers; try several approaches and measure the differences.

If you find that you must sort there are a few things to remember:

  • Use a stock sort; writing your own is a recipe for bugs.

  • Anything you can do before the sort that simplifies what you need to do during the sort is probably a good thing. If a sort runs in O(n log n) and you can make a one-time pass over your data to simplify the comparisons such that the sort can now run in O(n), you’re well ahead.

  • Think about the locality of reference of the sort algorithm you’re using versus the data that you expect it to run on.

There are fewer alternatives to searching than for sorting if you want to improve performance. If you need to do a search and if the search is time-critical, a binary search or hash table lookup is almost always the right answer. But again keep locality in mind. A linear search through a small array might be faster than a binary search through a data structure with a lot of pointers, which could cause page faults or cache misses.

MFC and Class Libraries

The Microsoft Foundation Class library (MFC) provides a framework that can greatly simplify writing code. Other class libraries are available for the same purpose. The following discussion is specific to MFC but is valid for similar idioms in other libraries.

When writing time-critical code, you should be aware of the overhead implied in using some of the classes. Examine the MFC code that your time-critical section is using to see if it meets your performance requirements. The following is a list of some performance issues you should be aware of in MFC.

  • CString The memory for a CString is dynamically allocated, which means it calls the C run-time library which in turn could call the operating system. So don’t use a CString simply to store a constant string; use const char *. Often a simple char array on the stack is the right answer.

    The CString class simplifies the writing of code that does string manipulation. Keep in mind, however, that any operation you perform with a CString object could imply a significant amount of overhead that could affect your performance. Step through the code that is generated to see exactly what is executed. It may be faster to use the run-time library string functions to have more complete control over what is executed. Generally speaking a CString is as efficient as any other dynamically allocated string, which means you bear the overhead of the dynamic allocation and release of memory.

  • CArray and CList The CArray and CList classes provide functionality to your MFC program that is not available to regular arrays. You may not need CArray if you know the specific limits necessary for the array; in that case you can just use a global fixed array. If you use CArray, you should use CArray::SetSize to establish its size and specify the number of elements by which to grow whenever a reallocation is necessary. If you do not use SetSize, adding elements could cause your array to be frequently reallocated and copied, which is inefficient and can fragment memory. You should also be aware that if you insert an item into an array, CArray will move subsequent items in memory. Before moving, CArray may need to grow the array. Both of these actions could cause cache misses or page faults. This is one of the things that is not obvious if you just use the CArray class members, and again you should step through the code that MFC uses to see if you can write something more specific to your scenario that would improve your code's performance. For example, you could provide CArray specializations for specific types, since it is a template.

    CList is a doubly-linked list, which means that element insertion is fast at the head, tail, and at a known POSITION in the list. A sequential search is necessary to look up an element by value or index. This search can be slow if the list is long. If your code just requires a singly-linked list, then you may want to reconsider using CList, whose overhead includes updating an additional pointer for all operations as well as the memory for that pointer. While the additional memory is not great, it is another opportunity for missed cache hits or page faults.

  • IsKindOf This function can generate many calls and potentially visit a lot of memory in different data areas (bad locality of reference), which you can observe as you step through the MFC source code. IsKindOf is useful for a debug build (in an ASSERT call, for example) but you should consider whether it can be avoided in a release build.

  • PreTranslateMessage function You should use PreTranslateMessage in cases where a particular tree of windows needs different keyboard accelerators. You can also use PreTranslateMessage where you must insert message handling into the message pump. PreTranslateMessage is the approved way of altering the way MFC dispatches messages. You should be careful to override PreTranslateMessage only at the level needed. For example, it is not necessary to override CMainFrame::PreTranslateMessage if all you are interested in is messages going to children of a particular view. In that case, just override PreTranslateMessage for the view class.

    You should not circumvent the normal dispatch path by using PreTranslateMessage to handle any message sent to any window. For this you should use window procedures and MFC message maps.

  • OnIdle function Idle events can occur at times you do not expect, such as between WM_KEYDOWN and WM_KEYUP events. Timers may be a more efficient way to trigger your desired behavior. Also, you should not force OnIdle to be called repetitively by generating false messages or by always returning TRUE from an override of OnIdle because this will never allow your thread to sleep. Again, a timer or a separate thread might be more appropriate.

Shared Libraries

Code reuse is desirable. However, if you are going to use someone else’s code, you should make sure you know exactly what it does in those cases where performance is critical to you. The best way to understand this is by stepping through the source code or by measuring with tools such as the profiler, PView, or Windows NT Performance monitor.

Heaps

Use multiple heaps with discretion. Additional heaps are created with HeapCreate and HeapAlloc and let you manage and then dispose of a related set of allocations. You don’t want to commit too much memory. If you’re using multiple heaps, pay special attention to the amount of memory that is initially committed.

Instead of multiple heaps, you may want to use helper functions to wrap the default heap. You can write helper functions to interface between your code and the default heap. Helper functions could facilitate custom allocation strategies that could improve the performance of your application. For example, if you perform many small allocations frequently, you may want to localize these allocations to one part of the default heap. You can allocate a large block of memory and then use a helper function to suballocate from that block. If you do this, you will not have additional heaps with unused memory because the allocation is coming out of the default heap.

On the other hand, using the default heap might get you less locality of reference than you desire. You really have to measure the effects of moving objects from heap to heap with tools such as the profiler, PView, Spy++, or Windows NT Performance monitor.

Measure your heaps so you can account for every allocation on the heap. Use the C run-time debug heap routines to checkpoint and dump your heap. You could then read the output into Excel and use pivot tables to view the results. Note the total number and size of allocations as well as the distribution of the allocations. You may want to compare these versus the size of working sets. You may also be interested in clustering of related-sized objects.

You can also use the Windows NT performance counters to monitor memory usage.

Threads

When you need a background task, threads may not be your best solution. Effective idle handling of the event may be a better solution. It’s easier to understand the locality of reference of your program with one thread than with two or more.

A good rule of thumb is that you should only use a thread if an operating system notification that you need to block on is at the root of the background work. Threads are best in such a case because it is not practical to block a main thread on an event.

Threads also present communication problems. You will have to manage the communication link between your threads, whether it be with a list of messages or by allocating and using shared memory. Managing your communication link will likely require synchronization to avoid race conditions and deadlock problems. Such complexity can easily turn into bugs and performance problems.

For addititonal information, see Idle Loop Processing and Multithreading Topics.

Small Working Set

Smaller working sets mean fewer page faults and more cache hits. This directly translates to into performance gains. We’ve mentioned locality of reference throughout this document; a small working set can mean good locality of reference. The process working set is the closest metric the operating system directly provides for telling you if you have good or bad locality of reference.

See SetProcessWorkingSetSize for information on how to set the upper and lower limits of the working set. See GetProcessWorkingSetSize for information on how to obtain the minimum and maximum working set sizes. You can use Spy++ or PView to view the size of the working set.


Procedures for Performance Tuning

Home | Overview | Details

This section will discuss how you can perform the various profiler-related procedures:

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

  • Enable Profiling

  • Run the Profiler from the Development Environment

  • Run the Profiler from the Command Line

  • Select Code to Profile

  • Produce a Tab-Delimited Profiler Report

  • Merge Profiler Output

  • Profile Dynamic-Link Libraries

  • Profile an OLE Server or ActiveX Control

  • Profile Inlined Code

  • Profile Multithreaded Applications

  • Profile on a “Quiet” Computer

  • Miscellaneous Profiler Restrictions


Enable Profiling

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Before using the profiler, you must build the current project with profiling enabled (equivalent to the command line setting LINK /PROFILE). If you want to perform function profiling only in the current project, you only need to enable profiling for the linker.

If you want to do line profiling, you also need to include debugging information.

To build your project for function profiling

  1. On the Build menu, click Settings to display the Project Settings dialog box.

  2. Click the Link tab.

  3. In the Category drop-down list box, click General.

  4. Select the Enable Profiling check box.

  5. Click OK.

  6. On the Build menu, click Build projectname.exe.

Note Selecting the Enable Profiling check box turns off incremental linking. To re-enable incremental linking, clear the Enable Profiling option.

To build your project for line profiling

  1. Perform the procedure to enable function profiling described earlier in this topic.

  2. Select the Generate Debug Info check box.

  3. Click the C/C++ tab.

  4. In the Category drop-down list box, click General.

  5. In the Debug Info drop-down list box, click Program Database or Line Numbers Only.

  6. Click OK.

  7. On the Build menu, click Build projectname.exe.

When the build is complete, the project is ready to be profiled.


Run the Profiler from the Development Environment

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The development environment will profile the active project’s target. To profile more than one project, you should use custom batch files; see Profiling Multiple .DLL and .EXE Files for more information.

See Select Code to Profile for information on how to specify which code shall be profiled.

To run the profiler from the development environment

On the Build menu, choose Profile to display the Profile dialog box, as shown in the figure below.

  1. In the Profile Type box, click one of the following option buttons:
    • Function Timing

    • Function Coverage

    • Line Coverage

    • Merge

    • Use Custom and the Custom Settings text box to run a batch file that contains profiler commands. See Run the Profiler from the Command Line for information on why you might want to batch and execute your own profiler commands. See Running a Custom Batch File for more information on specifying a batch file from the development environment.

    • Advanced settings is where you can specify PREP Phase I options.
  2. Click OK.

Profile Dialog Box

Note If you haven’t built your current project with profiling enabled, an error message lets you know that you need to rebuild your project. See Enable Profiling for more information.


Running a Custom Batch File

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

When a batch file is executed using the Custom option in the Profile dialog box, the development environment substitutes the project’s program name for the %1 parameter.

To specify your program’s command-line arguments

  1. On the Build menu, click Settings to display the Project Settings dialog box.

  2. Click the Debug tab and type the arguments in the Program arguments text box.

For more information on creating profiler batch files, see Run the Profiler from the Command Line.


Run the Profiler from the Command Line

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

You can issue profiler commands from your command line prompt. You can also place profiler commands in a batch file and execute them that way. See Profiling from the Command Line for more information on why you would use this method instead of profiling from within the development environment.

See Select Code to Profile for information on how to specify which code shall be profiled.

There are three topics that discuss running the profiler from the command line.

  • Using PROFILE, PREP, and PLIST

  • Profiler Batch Response Files

  • Standard Batch Files


Using PROFILE, PREP, and PLIST

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Profiling requires three separate programs: PREP, PROFILE, and PLIST. When you choose a standard option (other than Custom) from the Profile dialog box, the development environment executes these programs for you automatically, passing arguments to the PREP program.

If you want maximum profiling flexibility, including the ability to format your output and to specify function and line-count profiling, you must write your own batch files that invoke PREP, PROFILE, and PLIST. You can run these batch files from either the Profile dialog box or from the command prompt. If you run the batch file from the dialog box, the PLIST output will, by default, be routed to the output window. Command-line batch output can also be routed to a file.

The following figure illustrates the profiler batch processing flow.

Profiler Batch Processing Flow

Notice that the PREP program is called twice. Phase I is before the actual profiling and Phase II is after the profiling. The command-line arguments govern PREP’s behavior.

The .PBI, .PBO, and .PBT files are intermediate files that are used to transfer information between profiling steps. The broken lines indicate connections that depend on the PREP (Phase I) command-line options.

A typical profiler batch file might look like this:

PREP /OM /FT /EXC nafxcwd.lib %1
if errorlevel == 1 goto done
PROFILE %1 %2 %3 %4 %5 %6 %7 %8 %9
if errorlevel == 1 goto done
PREP /M %1
if errorlevel == 1 goto done
PLIST /SC %1 >%1.lst
:done

Note When you run a profiler batch file from the Profile dialog box using the Custom option, the PLIST standard output is routed to the Profile tab in the Output window. In the preceding batch file, the PLIST output is redirected to a file, as it would usually be in a batch file run from the command line.

When the batch file is run using the Custom option in the Profile dialog box, the development environment substitutes the project’s program name for the %1 parameter. You can specify your program’s command-line arguments on the Debug tab in the Project Settings dialog box.

If the preceding batch file was named FTIME.BAT, and you wanted to profile the program TEST from the Profile dialog box, you would select the Custom option, and then specify FTIME.BAT in the Custom Settings box. If you wanted to profile the TEST program from the command prompt, you would type:

FTIME TEST

Note If you are running a profiler batch file from the development environment, you can edit your batch file. Remember to save your batch files after editing, because the development environment does not save them automatically.


Profiler Batch Response Files

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

All three profiler programs accept response files. As a result, the command line:

PREP /OM /FT /EXC nafxcwd.lib %1

can be replaced by the line:

PREP @opts.rsp %1

if you create a file OPTS.RSP that contains this text:

/OM /FT /EXC nafxcwd.lib    # this is a comment

The number sign (#) in a response file defines a comment that runs through the end of the line.


Standard Batch Files

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Five standard batch files are included with the profiler:

Filename | Description
FTIME.BAT | Function timing
FCOUNT.BAT | Function counting
FCOVER.BAT | Function coverage
LCOUNT.BAT | Line counting
LCOVER.BAT | Line coverage

These batch files contain only the minimum parameters for PREP Phase I. Use them as prototypes for your own batch files, which should contain selection parameters. If you ran an unmodified LCOVER batch file for a Microsoft Foundation Class Library application, for example, the output file could be thousands of lines long.


Select Code to Profile

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

It usually doesn’t make much sense to profile an entire program, because in most applications for Windows, the majority of the application’s time is spent waiting for messages. Often, only one section of a program, such as repagination, might be performing poorly. Narrowing the region of code being profiled can speed up the execution of profiler sessions.

To narrow the area being profiled, see:

  • Specify Object Files, Libraries, and Lines to Profile

  • Select a Function to Profile


Specify Object Files, Libraries, and Lines to Profile

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

You can specify which object files and library files to profile in your program.

  • Using PROFILER.INI and TOOLS.INI

  • From the Command Line

  • From the Development Environment


Using PROFILER.INI and TOOLS.INI

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Upon invocation, the profiler looks in either one or two files for information about which object files and libraries to exclude. If neither of these files is present, profiling still continues. If exclude instructions exist in both files, all indicated object files and libraries will be excluded.

The PROFILER.INI file is created upon installation in \Program Files\Microsoft Visual Studio\VC98\bin . The [profiler] section of PROFILER.INI specifies libraries and object (.OBJ) files for the profiler to ignore. PROFILER.INI excludes object files and libraries from profiling that you would not ordinarily want to profile. By default, PROFILER.INI excludes the Win32 libraries, Microsoft Foundation Class (MFC) libraries, and C run-time libraries. View this file to see the complete list.

Whenever the profiler is run, it checks for the existence of the PROFILER.INI file in the same directory that the profiler executable files are located. If the file is present, it will exclude libraries and object files as indicated.

You should not modify PROFILER.INI, because if you reinstall Visual C++ the file will be overwritten.

TOOLS.INI is the file where you should specify additional object files and libraries to exclude from profiling. You have to create this file. You also have to set the INIT environment variable to the directory where TOOLS.INI can be found. For example, if you create TOOLS.INI in the root directory of your machine, you would set INIT to C:\.

As a sample, the following lines are taken from the default PROFILER.INI and represent the same format to use in TOOLS.INI. These commands exclude the common dialog and graphics device interface (GDI) libraries from profiling:

[profiler]
exclude:comdlg32.lib
exclude:gdi32.lib


From the Command Line

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

If you issue profile commands either from the command line or via a batch file, you can use the /EXC option in PREP Phase I.

If you want to exclude more than one object file or library with the /EXC option, you must preface each object file or library with the /EXC command.

For example, the following is a line from a sample batch file that excludes two object files, file1.obj and file2.obj, from profiling of program myprogram:

PREP /EXC file1.obj /EXC file2.obj myprogram.obj /FC %1

You can also use /EXCALL to exclude all object files and libraries and then use /INC to specify which object files and libraries to profile. For example, following is a line from a sample batch file that first excludes all object files and libraries and then includes file1.obj and file2.obj:

PREP /EXCALL /INC file1.obj /INC file2.obj /FC %1

You can even specify lines to profile in a source module. For example, if you only want to profile lines 32-96 (in source code) for a particular object file, you could issue

PREP /EXCALL /INC file1.cpp(32-96) /LC %1

Notice that you specify the lines directly from the source code file, which in this case has an extension of CPP.


From the Development Environment

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

If you are specifying function timing, function coverage, or line coverage from within the Profile dialog box, you can exclude object files or libraries from profiling by using /EXC, which is available in PREP Phase I, and the Advanced settings box.

For example, following is a line that you might type into the Advanced settings box that excludes two object files, file1.obj and file2.obj, from profiling:

/EXC file1.obj /EXC file2.obj

You can also use /EXCALL to exclude all object files and libraries and then use the /INC option to specify which object files and libraries to profile. For example, following is a line from a sample batch file that first excludes all object files and libraries and then includes file1.obj and file2.obj:

/EXCALL /INC file1.obj /INC file2.obj

You can even specify lines to profile in a source module. For example, if you only want to profile lines 32-96 (in source code) for a particular object file, you could issue

/EXCALL /INC file1.cpp(32-96)

Notice that you specify the lines directly from the source code file, which in this case has an extension of CPP.


Select a Function to Profile

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

With the /SF option (PREP Phase I) you can profile a selected function and the functions it calls, so you can easily isolate a routine and its children for analysis.

To profile only MyFunc and the functions it calls, you might use the following line for Phase I PREP in a batch file or at the command line.

PREP /SF ?MyFunc@@YAXPAH@@ /FC %1

Or, if you are in the development environment, you might type the following in the Advanced settings text box of the Profile dialog box,

SF ?MyFunc@@YAXPAH@@

Using function selection can give you more useful results than function exclusion/inclusion, but function selection can be slower.

Note When you specify a C++ function name to the profiler, you must provide its decorated name. The easiest way to get the decorated name is to look it up in the project’s .MAP file. For more information on C++ decorated names, see Decorated Names.


Produce a Tab-Delimited Profiler Report

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

In addition to formatted reports, the PLIST report-generation utility can produce a tab-delimited file of profiler output. The following sections describe the data format of the file, steps for analyzing statistics in the file, and a Microsoft Excel macro that uses this file format.

  • Exporting Data from the Profiler

  • Tab-Delimited File Format

  • Analyzing Profiler Statistics

  • Processing Profiler Output with Microsoft Excel


Exporting Data from the Profiler

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The PLIST /T command-line option causes PLIST to export the contents of a .PBT file into a tab-delimited format suitable for import into a spreadsheet or database. This format can also be used by user-written programs.

For example, to create a tab-delimited file called MYPROG.TXT from MYPROG.PBT, type:

PLIST /T MYPROG > MYPROG.TXT

Or, if you are using tokens in a batch file, you might use:

PLIST /T %1 > MYPROG.TXT

Note The ASCII tab-delimited format was designed to be read by other programs; it is not intended for general reporting.


Tab-Delimited File Format

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Every piece of data stored by the profiler is available through the tab-delimited file. Because not all aspects of the database are recorded by every profiling method, unused fields within a record may be zero. For example, the total time of the program will be zero if the program is profiled for counts only. Also, all included functions are listed for function counting and timing profiles, even if those functions were not executed.

The tab-delimited format is arranged with one record per line and two to eight fields per record. The following figure shows how a database looks when it is loaded into Microsoft Excel. This database was produced using the PLIST /T command-line option.

Tab-Delimited File in Microsoft Excel

The first item in each record is a format tag number. These tags range from 0 through 7 and indicate the kind of data given in the other fields of the record. The fields in each record are described in

  • Global Information Records

  • Local Information Records

Tab-delimited files are created with global information records first, organized in numerical order by format tag. The local information records, containing information about specific lines or functions, are created last. Local information records are organized by line number.

If the .PBT file contains information from more than one .EXE or .DLL file, the global information records will cover them all. Local information records include the Exe field, which specifies the name of the executable file that each record pertains to.


Global Information Records

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The global information records contain information about the entire .EXE file. The format tag numbers for global information records are 0 through 5. The record formats are as follows:

Profiling Banner Line Format

0 version banner

Field | Explanation
0 | Format tag number
version | PLIST version number
banner | PLIST banner

Profiling Method Line Format

1 method description

Field | Explanation
1 | Format tag number
method | Numeric value that indicates the profiling type (see the next table, “Profiling Types”)
description | ASCII description of the profiling type given by the Method field

The profiling types are listed in the following table.

Profiling Types

Method | Description
321 | Profile: Line counting, sorted by line
324 | Profile: Line coverage, sorted by line
521 | Profile: Function counting, sorted by function name
522 | Profile: Function timing, sorted by function name
524 | Profile: Function coverage, sorted by function name

Profiling Time and Depth Line Format

2 total time outside time call depth

Field | Explanation
2 | Format tag number.
total time | Total amount of time used by the program being profiled. This field is zero for counting and coverage profiles.
outside time | Amount of time spent before the first profiled function (with function profiling) or line (with line profiling) was executed. This field is zero for counting and coverage profiles.
call depth | Maximum number of nested functions found while profiling. Only profiled functions are counted. This field is zero for line profiling.

Profiling Hit Counts Line Format

3 total hits lines/funcs lines/funcs hit

Field | Explanation
3 | Format tag number
total hits | Total number of times the profiler detected a profiled line or function being executed
lines/funcs | Total number of lines or functions marked for profiling
lines/funcs hit | Number of marked lines or functions executed at least once while profiling

Profiling Date/Command Line Format

4 date command line

Field | Explanation
4 | Format tag number
date | Date and time that the profile was run (ASCII format)
command line | PLIST command-line arguments

Profiling Starting Function Name Line Format

5 starting function name

Field | Explanation
5 | Format tag number
starting function name | Decorated name of the starting function identified by the PREP /SF parameter


Local Information Records

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The local information records contain information about specific functions or lines that were profiled. The format tag numbers for local information records are 6 and 7. A file can have only one type of local information record. The line formats are as follows:

Profiling Function Information Line Format

6 exe source count time child func

Field | Explanation
6 | Format tag number.
exe | ASCII name of the executable file that contains the function.
source | ASCII name of the object module (including the .OBJ extension) that contains the function.
count | Number of times the function has been executed.
time | Amount of time spent executing the function in milliseconds. This field is zero for counting or coverage profiles.
child | Amount of time spent executing the function and any child functions it calls. This field is zero for counting or coverage profiles.
func | ASCII name of the function.

Profiling Line Information Line Format

7 exe source line count

Field | Explanation
7 | Format tag number.
exe | ASCII name of the executable file that contains the first line of this function.
Source | ASCII name of the source file that contains the first line of this function.
Line | Line number.
Count | Number of times the line has been executed. For coverage profiles, this field is 1 if the line has been executed and 0 otherwise.

Profiling Function-Attribution Stacks Line Format

8 number of stacks

Field | Explanation
8 | Format tag number
Number of stacks | Number of stacks for each function call

Profiling Stack Hits and Timing Line Format

9 stack size hit count stack time child time

Field | Explanation
9 | Format tag number
Stack size | Stack size for each function call
hit count | Hit count for this stack
Stack time | This stack’s self-time
Child time | This stack’s child-time

Profiling Stack Function Name Line Format

10 function name

Field | Explanation
10 | Format tag number.
Function name | Each function’s name on the stack. The number of names that appear here will be equal to the stack size field in the Profiling Stack Hits and Timing Line Format.


Analyzing Profiler Statistics

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The profiler tab-delimited file format can contain a considerable amount of information. You can process this data in a spreadsheet, database, or user-written program.

Below are some steps for analyzing profiler statistics.

  1. Collect the cumulative data from the global information records.

    These lines begin with the numbers 0 through 5. Each of these lines appears only once, and always in ascending order.

  2. Determine the type of database by finding the value of the Method field. This field is the second field of the first record in the tab-delimited file.

    If the value in the Method field is greater than 400, the file comes from function profiling. If it is less than 400, the file comes from line profiling. The type of information in the local information records given later is directly related to this value.

    In any one file, the local information records are always of the same type, either line information or function information.

  3. Process data from the local information records.

    For example, to calculate the percentage of hits on a given function, divide the value of the Count field in the sixth record in the file by the total number of hits from the Total Hits field in the third record.

  4. Send the results to a file or stdout.

    Note Remember that there can be only one type of local information record (either line or function information) in a file.


Processing Profiler Output with Microsoft Excel

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

PROFILER.XLM is a sample Microsoft Excel version 4.0 macro that processes the tab-delimited file and graphs the results. The macro is in the \Program Files\Microsoft Visual Studio\VC98\bin directory.

Note The profiler sample code is installed when you install Visual C++. If the Microsoft Excel macro and other sample code are not on your disk, run Setup again to reinstall the sample code.

The PROFILER.XLM macro is composed of four submacros. The first two macros, in columns A and B, are helper macros that copy and preprocess the data for use by the second pair of macros, in columns C and D. The macro in column C, labeled CreateColumnChart, creates a graph showing the number of times that each function or line was executed. The macro in column D is CreateColumnTimeChart; it works like CreateColumnChart, but operates on timing information.

  • Using the PROFILER.XLM Macro

  • Changing the PROFILER.XLM Selection Criteria


Using the PROFILER.XLM Macro

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

To run the PROFILER.XLM macro from within Microsoft Excel

  1. On the File menu, click Open to open PROFILER.XLM.

  2. On the File menu, click Open to open the tab-delimited file that was created by PLIST.

  3. If you have several open worksheets, activate the one containing the profiler data by clicking it with the mouse or by choosing its title from the Window menu.

  4. Run the macro:
    • Press CTRL+C for a chart based on hit counts.

    • Press CTRL+T for a chart based on timing. You cannot get a timing chart if the file contains only counting or coverage information.

The macro typically takes only a few seconds to run. When it is complete, Microsoft Excel displays a three-dimensional bar chart based on the results in the file (see the following figure). You can change the chart type by using the Gallery menu.

Graph Created with CreateColumnChart Macro

Note This macro copies the data in the file to another worksheet before processing it. The original tab-delimited file is left untouched.


Changing the PROFILER.XLM Selection Criteria

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The standard PROFILER.XLM macro displays hit counts greater than zero (for CTRL+C) and times greater than .01 millisecond (for CTRL+T). If you need to narrow these selections without analyzing the macro, edit the formulas in cells C10 and D10.


Merge Profiler Output

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

With the profiler’s modular design, you can make several profiling runs without having to run PREP each time (see the following figure). After PREP has created .PBI and .PBT files, you can reuse these files with PROFILE to create multiple .PBO files. You can then merge the .PBO files using the PREP /IO command-line option with multiple .PBO files. The Visual C++ Profile dialog box contains a Merge option button that automates this process.

Combining PROFILE Sessions

If you profile and merge with different data, you can see if all functions or lines are being tested.

If you are doing function timing, the times that you will see are cumulative times for the first profile run and all subsequent merge runs. To determine the average time, divide all times by the number of profiler runs.

  • Merge Profiler Output in the Development Environment

  • Merge Profiler Output from the Command Line

  • Reuse .PBT and .PBI Files


Merge Profiler Output in the Development Environment

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

After you perform the first profiler run in an application, you can merge output. After you have done one profiler run, a *.pbi file will exist in your project subdirectory.

Click the Merge button in the Profile dialog box.

Profile dialog box


Merge Profiler Output from the Command Line

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

If you need a single PLIST report from multiple profile runs, you must write and execute a batch file like this:

PREP /LV myprog.exe myfuncs.dll
PROFILE /O myprog1 myprog.exe
PROFILE /O myprog2 myprog.exe
PROFILE /O myprog3 myprog.exe
PREP /IT myprog /IO myprog1 /IO myprog2 /IO myprog3 /OT myprog
PLIST myprog >myprog.out

In this example, the program data can vary for each invocation of the PROFILE command. Then, the data is merged in the second PREP invocation.

Or, alternatively, because PREP Phase II adds data to an existing .PBT file:

PREP /LV myprog.exe myfuncs.dll
PROFILE myprog
PREP /M myprog
PROFILE myprog
PREP /M myprog
PROFILE myprog
PREP /M myprog
PLIST myprog >myprog.out

In this example, the output of the current profiler run is merged with the cumulative statistics from all previous profiler runs.

Note You can merge only eight .PBO files from the command line with each PREP invocation. To overcome this limitation, use PREP Phase II to merge groups of .PBO files into .PBT files. Then, merge the resulting .PBT files to yield a single .PBT file that contains statistics from the constituent .PBO files.

You cannot merge .PBO or .PBT files from different .PBI files. PREP can combine information only from profiling sessions that use the same .EXE and .PBI files (and therefore have identical profiling characteristics). You cannot, for example, merge the results of a timing session with the results of a coverage session.


Reuse .PBT and .PBI Files

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

For a large program, it can take a lot of time for PREP to create .PBT and .PBI files from scratch. You must rebuild these files if you change your source code or the profiling method, but you can reuse the files if you only need another profile run with different program input data. Just copy the .PBT file after the initial Phase I PREP run. The .PBI file is never changed, so you don’t need to copy it.


Profile Dynamic-Link Libraries

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Profiling a dynamic-link library (DLL) is similar to profiling an .EXE file. When you profile a DLL, you follow the same steps and use the same commands that you would for an .EXE file. The same profiling rules that apply to .EXE files (such as the need to include debugging information and to supply a .MAP file) apply to DLLs.

  • Profiling DLLs from a Batch File

  • Profiling Multiple .DLL and .EXE Files

  • Program Statistics vs. Module Statistics


Profiling DLLs from a Batch File

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

For function profiling, the DLL is typically renamed with an _LL extension, but the .EXE file looks for a file with a .DLL extension when it executes. Therefore the prepared DLL must be renamed prior to profiling.

The following batch file (PROFDLL.BAT) profiles a DLL with the assumption that the .EXE file has not been prepared for profiling:

COPY %1.dll save
PREP /OM %1.dll
COPY %1._ll %1.dll
PROFILE /I %1 /O %1 %2 %3 %4 %5 %6
COPY save %1.dll
PREP /M %1
PLIST %1

Note The preceding batch generates a message warning you that the main program has not been prepared for profiling.

If you had a main program HEARTS.EXE that used a DLL called CARDS.DLL, and you wanted to profile only CARDS.DLL, you would run the preceding batch as:

PROFDLL cards hearts


Profiling Multiple .DLL and .EXE Files

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Up to 16 DLLs and their calling executable can be profiled in a single run when using the Phase I PREP command line options.

The following commands demonstrate how to profile an executable file and two DLLs from the command line:

PREP /OM /FC wingame.exe aliens.dll hiscore.dll
PROFILE wingame.exe
PREP /M  wingame
PLIST wingame >wingame.out

The first line causes PREP to create WINGAME.PBI and WINGAME.PBT files that include information on WINGAME.EXE, ALIENS.DLL, and HISCORE.DLL. The next line causes PROFILE to run WINGAME.EXE (actually WINGAME._XE, as generated by PREP Phase I). During the execution of WINGAME, PROFILE collects statistics for WINGAME.EXE as well as ALIENS.DLL and HISCORE.DLL, if they are called. The final two lines process the information from the profiling session and store the results in WINGAME.OUT.


Profile a COM or OLE Server or ActiveX Control

Profile an OLE Server or ActiveX Control

Home | Overview | Details

Profile Dynamic-Link Libraries explains the steps involved in profiling dynamic-link libraries and profiling multiple .DLL and .EXE files.

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Since an OLE server is basically an EXE or a DLL, and an ActiveX control (formerly OLE control) is a DLL even though it has an extension of .OCX, profiling them is similar to profiling an EXE or a DLL. When you profile an OLE server or ActiveX control, you follow the same steps and use the same commands that you would for an EXE or a DLL. The same profiling rules that apply to EXEs and DLLs (such as the need to include debugging information and to supply a .MAP file) apply to OLE servers and ActiveX controls.

The four examples below illustrate the steps required to profile a full OLE server, a mini OLE server, an in-process Automation server (formerly OLE Automation server), and an ActiveX control.

You may need to register the mini OLE server, the in-process Automation server, or the ActiveX control explicitly. You can do one of the following steps to register them:

  • For a DLL (and thus for an ActiveX control), run REGSVR32 from the command prompt. Alternatively, you can open the corresponding project in the development environment and select the Register Control option from the Tools menu.

  • For an EXE, simply run the executable file. You may not be able to run it or you may get a message saying, "This server can only be run from a container application," but you can click OK. It will have been registered.

In order to run the profiler, you may need to copy the \Program Files\Microsoft Visual Studio\VC98\bin \PROFILE.DLL file to the directory containing the file that you are profiling, or to one of the system directories.

Each step in the following examples is a command at the command prompt. Alternatively, you could create a batch file with these commands.

To profile a full OLE server or an Automation server:

PREP /OM /FT FullSrvr
PROFILE FullSrvr
PREP /M FullSrvr
PLIST FullSrvr > FullSrvr.txt

where FullSrvr.exe is the file corresponding to a full OLE server or Automation server.

To profile a mini OLE server:

COPY MiniSrvr.exe MiniSrvr.sav
PREP /OM /FT MiniSrvr
COPY MiniSrvr._xe MiniSrvr.exe
PROFILE /I MiniSrvr /O MiniSrvr Container
PREP /M MiniSrvr
PLIST MiniSrvr > MiniSrvr.txt
COPY MiniSrvr.sav MiniSrvr.exe

where MiniSrvr is the file corresponding to a mini OLE server and Container is a container application that runs the MiniSrvr.

To profile an in-process Automation server (the steps are similar to those of a mini OLE server except that you have a .dll extension instead of .exe):

COPY InProc.dll InProc.sav
PREP /OM /FT InProc.dll
COPY InProc._ll InProc.dll
PROFILE /I InProc /O InProc Client
PREP /M InProc
PLIST InProc > InProc.txt
COPY InProc.sav InProc.dll

where InProc is the file corresponding to an in-process Automation server and Client is an Automation client application that drives the InProc.dll.

To profile an ActiveX control with an .ocx extension (the steps are similar again except that you have an .ocx extension):

COPY Control.ocx Control.sav
PREP /OM /FT Control.ocx
COPY Control._cx Control.ocx
PROFILE /I Control /O Control ControlContainer
PREP /M Control
PLIST Control > Control.txt
COPY Control.sav Control.ocx

where Control is the ActiveX control and ControlContainer is an ActiveX control container application.


Profile Inlined Code

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

If you specify, the Visual C++ compiler will perform inlining, which replaces a function call with an actual copy of the code. Profiling inlined code requires special attention.

  • Function Profiling for Inlined Functions

  • Line Profiling for Inlined Functions


Function Profiling for Inlined Functions

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Because inlined functions don’t generate .MAP file entries or CALL instructions, the profiler cannot tell when the computer is executing one of these functions. The time, hit, and coverage data will be attributed to the “calling” function.

Note In many cases there are .MAP file entries for “inlined” functions because the functions are not necessarily inlined everywhere in the application. Take this into account when you analyze profiler results.


Line Profiling for Inlined Functions

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The profiler can provide line-level hit count and coverage information for inlined functions. Be sure to include the source lines in the Phase I PREP command-line options, just as you would include source lines in the calling program.


Profile Multithreaded Applications

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

For multithreaded applications, profiler behavior depends on the profiling method.

For line counting and line coverage, the profiler does not discriminate among threads. The hit counts encompass all the program’s threads.

For function timing, function counting, and function coverage, profiling is thread-dependent. You can profile an individual thread by (1) declaring the thread’s main function as the starting function (PREP /SF option), and (2) including all functions in the program (don’t use the PREP /EXC option).

The profile results will be difficult to interpret if you do not specify a starting function, if you specify a starting function that is called from multiple threads, or if you don’t include all functions.


Profile on a "Quiet" Computer

Profile on a “Quiet” Computer

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

For maximum profiler accuracy, close as many other applications as possible during profiling. In particular, do not run programs such as electronic mail that execute at random intervals. If you have a network connection, you might want to disconnect it as well, since networks can cause differences in profile results.


Miscellaneous Profiler Restrictions

Home | Overview | Details

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Function-level profiling works only with ordinary functions that return with the stack pointer unchanged. Profiling should be turned off for functions that change the stack pointer or store the return address for later use. The profiler automatically turns off profiling for the functions alloca and setjmp. If you write your own similar functions, you must write them in assembly language. By default, assembly-language functions are excluded from profiling. Do not use these functions with the PREP /INC option.


Articles That Tell About Performance Tuning

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The profiler-related articles are as follows:

  • PREP

  • PROFILE

  • PLIST

  • Profiler Won't Merge Statistics from Two Different Operating Systems on the Same Computer

  • Profiler Will Not Profile DLLs That Are Freed, Then Reloaded

  • Onboard System Memory Cache and Disk Caches May Affect Profile Times

  • Profiling Windows NT Services

  • Error Writing to .PDB File After Line Profile Operation

  • PRB: Profiler Fatal Errors PRF1012 and PRF1306


PREP

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The PREP program runs twice during a normal profiling operation. In Phase I, it reads an executable (.EXE) file and then creates .PBI and .PBT files. In Phase II, it reads .PBT and .PBO files and then writes a new .PBT file for PLIST.

Syntax

PREP [options] [programname1] [programname2...programname8]

PREP reads the command line from left to right, so the rightmost options override contradictory options to the left. None of the options is case sensitive. You must prefix options with a forward slash (/) or a dash (–), and options must be separated by spaces.

Parameter | Description
options | See Options below.
programname1 | Filename of primary program to profile (.DBG, .EXE, or .DLL). PROFILE adds the .EXE extension if no extension is given. This parameter must be specified for PREP Phase I, but not for Phase II.
programname2... programname8 | Additional programs to profile. These parameters can be specified for PREP Phase I only.

An ‘X’ in the following Options table indicates that a PREP command-line option applies to a particular phase.

Options

PREP Phase I options can be issued either from the Profiler dialog box or from the command line. PREP Phase II options can be issued only at the command line.

Option | I | II | Description
/AT | X |  | Collects attribution data for function timing and function counting. Function attribution reports which function called another function. See the /STACK switch later in this list.
/CB | X |  | Used with function timing, allows you to set the calibrated overhead of profiler calls in the event that your function timing calls have varied because of varied calibrated overhead values. The calibrated overhead is displayed in default (non-tab-delimited) PLIST output.
/EXC | X |  | Excludes a specified module from the profile. You can also exclude part of a module. For example, /EXC test.cpp(9-18).
/EXCALL | X |  | Excludes all modules from the profile (see Remarks). Used with /INC.
/FC | X |  | Selects function count profiling.
/FT | X |  | Selects function timing profiling. This option causes the profiler to generate count information as well. This is the default setting from the command line.
/FV | X |  | Selects function coverage profiling.
/INC | X |  | Includes in profile (see Remarks). Used in conjunction with /EXCALL.
/H[ELP] | X | X | Provides a short summary of PREP options.
/IO filename |  | X | Merges an existing .PBO file (PROFILE output). Up to eight .PBO files can be merged at a time. The default extension is .PBO.
/IT filename |  | X | Merges an existing .PBT file (PREP Phase I output). Up to eight .PBT files can be merged at a time. You cannot merge .PBT files from different profiling methods. The default extension is .PBT.
/LC | X |  | Selects line count profiling. May take a long time.
/LV | X |  | Selects line coverage profiling.
/M filename |  | X | Substitutes for the /IT, /IO, and /OT options.
/NOLOGO | X | X | Suppresses the PREP copyright message.
/OI filename | X |  | Creates a .PBI file. The default extension is .PBI. If /OI is not specified, the output .PBI file is programname1.PBI.
/OM | X |  | Creates a self-profiling file with an _XE or _LL extension for function timing, function counting, and function coverage. Without this option, the executable code is stored in the .PBI file. This option speeds up profiling.
/OT filename | X | X | Specifies the output .PBT file. The default extension is .PBT. If /OT is not specified, the output .PBT file is programname1.PBT.
/SF function | X |  | Starts profiling with function. The function name must correspond to an entry in the .MAP file.
/STACK dpt | X |  | When using the /AT switch, you can also set the stack depth (dpt) to which functions will have their attribution data recorded.
/? | X | X | Provides a short summary of PREP options.

Environment Variable

PREP Specifies default command-line options.

If a value for the PREP environment variable is not specified, the default options for PREP are:

/FT /OI filename /OT filename

where filename is set to the programname1 parameter value.

Remarks

The /INC and /EXC options specify individual library (.LIB), object (.OBJ), and application source (.C, .CPP, or .CXX) files. For line counting and line coverage, you can specify line numbers with source files as:

/EXCALL /INC test.cpp(3-41,50-67)

This example includes only lines 3 through 41 and lines 50 through 67 from the source file TEST.CPP. Note the absence of spaces in the source specification.

To specify all source lines in a particular module, specify the .OBJ file as:

/EXCALL /INC test.obj

or by using the source filename with zero line numbers like this:

/EXCALL /INC test.cpp(0-0)

The following statement profiles from line 50 to the end of the file:

/EXCALL /INC test.cpp(50-0)


PROFILE

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

PROFILE profiles an application and creates a .PBO file of the results. Use PROFILE after creating a .PBI file with PREP.

Syntax

PROFILE [options] programname [programargs]

PROFILE reads the command line from left to right, so the rightmost options override contradictory options to the left. None of the options is case sensitive. You must prefix options with a forward slash (/) or a dash (–), and options must be separated by spaces.

If you do not specify a .PBO filename on the command line, PROFILE uses the base name of the .PBI file with a .PBO extension. If you do not specify a .PBI or a .PBO file, PROFILE uses the base name of programname with the .PBI and .PBO extensions.

Parameter | Description
options | See Options below.
programname | Filename of the program to profile. PROFILE adds the .EXE extension if no extension is given. See Remarks.
programargs | Optional command-line arguments for programname. See Remarks.

Options

Option | Description
/A | Appends any redirected error messages to an existing file. If the /E command-line option is used without the /A option, the file is overwritten. This option is valid only with the /E option.
/E filename | Sends profiler error messages to filename.
/H[ELP] | Provides a short summary of PROFILE options.
/I filename | Specifies a .PBI file to be read. This file is created by PREP.
/NOLOGO | Suppresses the PROFILE copyright message.
/O filename | Specifies a .PBO file to be created. Use the PREP utility to merge with other .PBO files, or to create a .PBT file for use with PLIST.
/X | Returns the exit code of the program being profiled.
/? | Provides a short summary of PROFILE options.

Remarks

You must specify the filename of the program to profile on the PROFILE command line. PROFILE assumes the .EXE extension if no extension is given.

You can follow the program name with command-line arguments; these arguments are passed to the profiled program unchanged.

If you are profiling code in a dynamic-link library (.DLL) file, give the name of an .EXE file that calls it. For example, if you want to profile SAMPLE.DLL, which is called by CALLER.EXE, you can type:

PROFILE CALLER.EXE

assuming that CALLER.PBI has SAMPLE.DLL selected for profiling. For more information, see Profile Dynamic-Link Libraries.

Environment Variable

PROFILE Specifies default command-line options.

If the PROFILE environment variable is not specified, there are no other default options.


PLIST

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

PLIST converts results from a .PBT file into a formatted text file.

Syntax

PLIST [options] inputfile

PLIST reads the command line from left to right, so the rightmost options override contradictory options to the left. None of the options is case sensitive. You must prefix options with a forward slash (/) or a dash (–), and options must be separated by spaces.

PLIST results are sent to STDOUT by default. Use the greater-than (>) redirection character to send these results to a file or device.

PLIST must be run from the directory in which the profiled program was compiled.

Parameter | Description
options | See Options below.
inputfile | The .PBT file to be converted by PLIST.

Options

Option | Description
/C count | Specifies the minimum hit count to appear in the listing.
/D directory | Specifies an additional directory for PLIST to search for source files. Use multiple /D command-line options to specify multiple directories. Use this option when PLIST cannot find a source file.
/F | Lists full paths in a tab-delimited file.
/FLAT | When using function attribution (see PREP /AT), displays function attribution with no indentation.
/H[ELP] | Provides a short summary of PLIST options.
/INDENT | When using function attribution (see PREP /AT), displays function attribution information in indented format. This is the default display for function attribution if neither /FLAT nor /TAB is selected.
/NOLOGO | Suppresses the PLIST copyright message when output is directed to the screen.
/PL length | Sets page length (in lines) of output. The length must be 0 or in the range 15 through 255. A length of 0 suppresses page breaks. The default length is 0.
/PW width | Sets page width (in characters) of output. The width must be in the range 1 through 511. The default width is 511.
/SC | Sorts output by counts, highest first.
/SL | Sorts output in the order that the lines appear in the file. This is the default setting. This option is available only for line profiling.
/SLS | Forces line count profile output to be printed in coverage format.
/SN | Sorts output in alphabetical order by function name. This option is available only for function profiling.
/SNS | Displays function timing or function counting information in function coverage format. Sorts output in alphabetical order by function name.
/ST | Sorts output by time, highest first.
/T | Tab-separated output. Creates a tab-delimited database from the .PBT file for export to other applications. All other options, including sort specifications, are ignored when using this option.
/TAB indent | When using function attribution (see PREP /AT), sets tab width for indentation of function information.
/? | Provides a summary of PLIST options.

Environment Variable

PLIST Specifies default command-line options.

If the PLIST environment variable is not specified, the default options for PLIST depend on the profile type, as shown in the following table.

Profile type | Sort option | Hit count option
Function timing | /ST | /C 1
Function counting | /SC | /C 1
Function coverage | /SN | /C 0
Line counting | /SL | /C 0
Line coverage | /SLS | /C 0


Profiler Won't Merge Statistics from Two Different Operating Systems on the Same Computer

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The profiler tools will not merge profile sessions run on two different operating systems. For example, if you copy the profiler sessions from Windows NT to a Windows 95 machine and try to merge the sessions, the profiler will generate this error:

PREP : fatal error PRF1463: different clock/sampling frequency

Do not attempt to merge profiling statistics gathered when profiling on two different operating systems. This behavior is by design.

To reproduce this behavior

  1. Start a sample project and enable profiling in the Project Settings dialog box (Build menu, Settings command).

  2. Build the project.

  3. Run the profiler by clicking Profile on the Build menu with Function Timing selected.

  4. Exit, and start a different operating system; that is, if you were in Windows 95, start Windows NT, or vice versa.

  5. From the development environment, run the profiler by clicking Profile on the Build menu with Merge selected.

Note The error doesn't appear if the profiling was done with the same operating system but on different computers. It will merge the timing statistics even though the results may not be consistent.


Profiler Will Not Profile DLLs That Are Freed, Then Reloaded

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Microsoft Source Profiler version can profile the first instance of any and all DLLs (dynamic-link libraries) in a Windows application, but it cannot continue to collect statistics for a dynamically loaded DLL that is freed and then reloaded.

DLLs that are dynamically loaded with LoadLibrary( ), and that are freed and then reloaded, should not be profiled because the results will not be correct.

This behavior can be observed by attempting to profile code that performs the following actions:

  1. Dynamically loads a DLL with LoadLibrary( ).

  2. Frees the DLL with FreeLibrary( ).

  3. Reloads the DLL with LoadLibrary( ).

There is currently no way to work around this limitation. The ability to handle dynamically reloaded DLLs under Windows is being considered for a future version of the profiler.


Program Statistics vs. Module Statistics

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

PLIST reports always start with a “Program Statistics” section followed by a “Module Statistics” section. If there are several DLLs involved, as in the previous example, there is one “Module Statistics” section per .EXE or .DLL. The “Program Statistics” section lists totals for the entire program, including DLLs. Total time includes time in functions and modules not being profiled.


Onboard System Memory Cache and Disk Caches May Affect Profile Times

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

The Microsoft Source Profiler may display erratic execution times on any system with an Intel 80386 or 80486 processor that has a built-in memory cache. The only effective way to work around this is to disable the cache, because there is no way to control what is cached and what is not cached.

The erratic profile results are caused by the way a memory cache of this type operates. If code from the program being profiled is in the cache, the execution times will be less than normal. On the other hand, it's likely that the cache will be dominated by the Profiler itself, since the instructions from the Profiler's own code will usually be in the cache. This may then result in increased times for the program being profiled. Caching will also affect small programs more than large ones because of the successful hit rate in the cache.

Because memory caching hinders accurate profiling, a system without a cache should be used while profiling to ensure the most reliable times. In any case, the overall effect of a cached system should be that it runs faster, so it should not be necessary to consider this net gain when profiling.


Profiling Windows NT Services

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

This topic provides information about profiling Windows NT service processes.

Use the service sample from the directory samples\sdk\winnt\service (after you install this SDK sample), and follow these steps to get timing information for its service functions:

To profile Windows NT Services

  1. Set necessary environment variables using the System control panel. You will find system environment variables like ComSpec, windir, and Path.

  2. Add two new environment variables:
    __ProfilePBI=<full path of your PBI file>
__ProfilePBO=<full path of your PBO file>

    Note the exact spelling and two leading underscores. If these are not correctly set, you will get messages from PROFILE.DLL warning you that these settings cannot be found.

    In this example, if your compiler is on your D drive, these variables would be:

    d:\...\samples\sdk\winnt\service\simple.pbi
d:\...\samples\sdk\winnt\service\simple.pbo
  3. Copy the profiler DLL, PROFILE.DLL, from the Program Files\Microsoft Visual Studio\VC98\bin subdirectory to either the directory where the service .EXE resides or to one of the directories listed in the PATH environment variable.

  4. Build the sample, SIMPLE.EXE. Instruct the linker to create a .MAP file.

  5. Run PREP to create SIMPLE._XE, which has been modified for profiling:
    prep /om /ft /sf _worker_thread simple.exe

    This command also sets up the code to follow the call stack from the worker_thread() routine. By default, the profiler profiles calls from the main thread, so servicing requests from a secondary thread without specifying the /sf option will produce incomplete results. In the sample, this second thread is created by calling CreateThread( ) to service the requests. If the main thread was servicing the requests, you wouldn't need to use the /sf option.

  6. Copy SIMPLE._XE to SIMPLE.EXE. This overwrites the original executable file with the modified version, which has the profile hooks added to the code.

  7. Start the service by using the Services program in the Control Panel, and run the client application. Stop the service using the Control Panel. You can get the timing information by executing the following commands from the command prompt:
    prep /m simple
plist simple


Error Writing to .PDB File After Line Profile Operation

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Attempting to build or rebuild a project after doing a line profile operation on the project may result in the following error message:

  LNK1201: error writing to program database "c:\Microsoft Visual Studio\Common\msdev98\MyProjects\yourapp\Debug\yourapp.pdb"; check for insufficient disk space

The Development Environment does not close the project's program database file (.PDB) after doing a line profile. Upon attempting to rebuild the project, the linker cannot write to the project's .PDB file, causing the LNK1201 error.

There are a number of ways to work around this problem:

  • Exit the development environment then restart and reload your project.

  • Run the project under the debugger. Choose the Debug command from the Build menu (F5). Close the application or stop debugging. This will close the .PDB file.

  • Use a batch file to line profile your application. This can easily be done by specifying the LCOVER.BAT file in the Profile dialog box's Custom Settings.


Profiler Fatal Errors PRF1012 and PRF1306

Home | Overview | How Do I

Feature Only in Professional and Enterprise Editions Profiling is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

When trying to profile a program using the Visual C++ development environment, you may get the following fatal error messages:

PROFILE.DLL : fatal error PRF1012 : cannot read expected number of bytes from file <path>\xxxx.pbi
PREP : fatal error PRF1306: PBT or PBO file <path>\xxxx.pbo is not derived from same PBI file

It is also possible to get the following error if you are using the incorrect PROFILE.DLL:

PROFILE.DLL: fatal error PRF1005: operating system ran out of memory.

All these error messages are caused by the wrong version of PROFILE.DLL being loaded in memory and used by the profiler. Most likely a copy of PROFILE.DLL from Visual C++, 32-bit Edition, version 1.0 has been loaded by Windows NT.

To correct the situation, make sure the PROFILE.DLL from Visual C++ version 2.0, 2.1 or later is used by the profiler. Do a file search on your system to determine where the older PROFILE.DLL is located, and rename or delete the file. Make sure that the only PROFILE.DLL on your system is located in the Program Files\Microsoft Visual Studio\VC98\bin directory for Visual C++.

If for some reason there is no PROFILE.DLL in the Program Files\Microsoft Visual Studio\VC98\bin directory, you can restore the file by running Visual C++'s setup program and doing a custom installation. To do this, clear all options in the 'Tools Options' dialog box except for 'Profiler'. You also need to make sure the installation directory you specify is the same as your current Visual C++ installation.

The incorrect PROFILE.DLL will probably be found in the winnt\SYSTEM32 directory where winnt refers to the directory that Windows NT is installed. Or the DLL may be in another directory found on the PATH. The correct file should be located in the Visual C++ Program Files\Microsoft Visual Studio\VC98\bin directory.

The date and size of the PROFILE.DLL files from the most recent Visual C++ 32-bit Edition versions prior to 6.0 are listed here:

  • Visual C++ 5.0 : 10/01/97 10:47p 107,520 PROFILE.DLL

  • Visual C++ 4.2 : 02/08/96 07:48p 93,184 PROFILE.DLL

  • Visual C++ 4.1 : 02/08/96 07:48p 93,184 PROFILE.DLL

  • Visual C++ 4.0 : 09/29/95 09:49p 78,848 PROFILE.DLL


Preprocessor Reference

This reference explains the preprocessor as it is implemented in Microsoft® C/C++. The preprocessor performs preliminary operations on C and C++ files before they are passed to the compiler. The preprocessor allows you to:
  • Define and undefine macros.
  • Expand macros.
  • Conditionally compile code.
  • Insert specified files.
  • Specify compile-time error messages.
  • Apply machine-specific rules to specified sections of code.
What do you want to know more about?
Preprocessor directives.
Preprocessor operators.
Predefined macros.
Pragmas.

Interesting home pages
Visual C++ Home The entire Visual C++ product.
C/C++ Language Quick Reference Reference of language elements -- keywords and operators.
Compiling and Linking Building your program.


The Preprocessor

The preprocessor is a text processor that manipulates the text of a source file as part of the first phase of translation. The preprocessor does not parse the source text, but it does break it up into tokens for the purpose of locating macro calls. Although the compiler ordinarily invokes the preprocessor in its first pass, the preprocessor can also be invoked separately to process text without compiling.

Microsoft Specific

You can obtain a listing of your source code after preprocessing by using the /E or /EP compiler option. Both options invoke the preprocessor and output the resulting text to the standard output device, which, in most cases, is the console. The difference between the two options is that /E includes #line directives and /EP strips these directives out.

END Microsoft Specific

Special Terminology

In the preprocessor documentation, the term “argument” refers to the entity that is passed to a function. In some cases, it is modified by “actual” or “formal,” which mean the argument expression specified in the function call and the argument declaration specified in the function definition, respectively.

The term “variable” refers to a simple C-type data object. The term “object” refers to both C++ objects and variables; it is an inclusive term.


Phases of Translation

C and C++ programs consist of one or more source files, each of which contains some of the text of the program. A source file, together with its include files (files that are included using the #include preprocessor directive) but not including sections of code removed by conditional-compilation directives such as #if, is called a “translation unit.”

Source files can be translated at different times — in fact, it is common to translate only out-of-date files. The translated translation units can be kept either in separate object files or in object-code libraries. These separate translation units are then linked to form an executable program or a dynamic-link library (DLL).

Translation units can communicate using:

  • Calls to functions that have external linkage.

  • Calls to class member functions that have external linkage.

  • Direct modification of objects that have external linkage.

  • Direct modification of files.

  • Interprocess communication (for Microsoft Windows-based applications only).

The following list describes the phases in which the compiler translates files:

Character mapping

Characters in the source file are mapped to the internal source representation. Trigraph sequences are converted to single-character internal representation in this phase.

Line splicing

All lines ending in a backslash (\) and immediately followed by a newline character are joined with the next line in the source file, forming logical lines from the physical lines. Unless it is empty, a source file must end in a newline character that is not preceded by a backslash.

Tokenization

The source file is broken into preprocessing tokens and white-space characters. Comments in the source file are replaced with one space character each. Newline characters are retained.

Preprocessing

Preprocessing directives are executed and macros are expanded into the source file. The #include statement invokes translation starting with the preceding three translation steps on any included text.

Character-set mapping

All source-character-set members and escape sequences are converted to their equivalents in the execution-character set. For Microsoft C and C++, both the source and the execution character sets are ASCII.

String concatenation

All adjacent string and wide-string literals are concatenated. For example, "String " "concatenation" becomes "String concatenation".

Translation

All tokens are analyzed syntactically and semantically; these tokens are converted into object code.

Linkage

All external references are resolved to create an executable program or a dynamic-link library.

The compiler issues warnings or errors during phases of translation in which it encounters syntax errors.

The linker resolves all external references and creates an executable program or DLL by combining one or more separately processed translation units along with standard libraries.


Preprocessor Directives

Preprocessor directives, such as #define and #ifdef, are typically used to make source programs easy to change and easy to compile in different execution environments. Directives in the source file tell the preprocessor to perform specific actions. For example, the preprocessor can replace tokens in the text, insert the contents of other files into the source file, or suppress compilation of part of the file by removing sections of text. Preprocessor lines are recognized and carried out before macro expansion. Therefore, if a macro expands into something that looks like a preprocessor command, that command is not recognized by the preprocessor.

Preprocessor statements use the same character set as source file statements, with the exception that escape sequences are not supported. The character set used in preprocessor statements is the same as the execution character set. The preprocessor also recognizes negative character values.

The preprocessor recognizes the following directives:

#define | #error | #import | #undef
#elif | #if | #include |
#else | #ifdef | #line |
#endif | #ifndef | #pragma |

The number sign (#) must be the first nonwhite-space character on the line containing the directive; white-space characters can appear between the number sign and the first letter of the directive. Some directives include arguments or values. Any text that follows a directive (except an argument or value that is part of the directive) must be preceded by the single-line comment delimiter (//) or enclosed in comment delimiters (/* */). Lines containing preprocessor directives can be continued by immediately preceding the end-of-line marker with a backslash (\).

Preprocessor directives can appear anywhere in a source file, but they apply only to the remainder of the source file.


The #define Directive

You can use the #define directive to give a meaningful name to a constant in your program. The two forms of the syntax are:

Syntax

#define identifier token-stringopt

#define identifier[( identifieropt, ... , identifieropt )] token-stringopt

The #define directive substitutes token-string for all subsequent occurrences of an identifier in the source file. The identifier is replaced only when it forms a token. (See C++ Tokens in the C++ Language Reference.) For instance, identifier is not replaced if it appears in a comment, within a string, or as part of a longer identifier.

A #define without a token-string removes occurrences of identifier from the source file. The identifier remains defined and can be tested using the #if defined and #ifdef directives.

The token-string argument consists of a series of tokens, such as keywords, constants, or complete statements. One or more white-space characters must separate token-string from identifier. This white space is not considered part of the substituted text, nor is any white space following the last token of the text.

Formal parameter names appear in token-string to mark the places where actual values are substituted. Each parameter name can appear more than once in token-string, and the names can appear in any order. The number of arguments in the call must match the number of parameters in the macro definition. Liberal use of parentheses ensures that complicated actual arguments are interpreted correctly.

The second syntax form allows the creation of function-like macros. This form accepts an optional list of parameters that must appear in parentheses. References to the identifier after the original definition replace each occurrence of identifier( identifieropt, ..., identifieropt ) with a version of the token-string argument that has actual arguments substituted for formal parameters.

The formal parameters in the list are separated by commas. Each name in the list must be unique, and the list must be enclosed in parentheses. No spaces can separate identifier and the opening parenthesis. Use line concatenation — place a backslash (\) before the newline character — for long directives on multiple source lines. The scope of a formal parameter name extends to the new line that ends token-string.

When a macro has been defined in the second syntax form, subsequent textual instances followed by an argument list constitute a macro call. The actual arguments following an instance of identifier in the source file are matched to the corresponding formal parameters in the macro definition. Each formal parameter in token-string that is not preceded by a stringizing (#), charizing (#@), or token-pasting (##) operator, or not followed by a ## operator, is replaced by the corresponding actual argument. Any macros in the actual argument are expanded before the directive replaces the formal parameter. (The operators are described in Preprocessor Operators.)

The following examples of macros with arguments illustrate the second form of the #define syntax:

// Macro to define cursor lines
#define CURSOR(top, bottom) ((top) << 8) | bottom))

// Macro to get a random integer with a specified range
#define getrandom(min, max) \
    ((rand()%(int)(((max) + 1)-(min)))+ (min))

Arguments with side effects sometimes cause macros to produce unexpected results. A given formal parameter may appear more than once in token-string. If that formal parameter is replaced by an expression with side effects, the expression, with its side effects, may be evaluated more than once. (See the examples under Token-Pasting Operator (##).)

The #undef directive causes an identifier’s preprocessor definition to be forgotten. See The #undef Directive for more information.

If the name of the macro being defined occurs in token-string (even as a result of another macro expansion), it is not expanded.

A second #define for a macro with the same name generates an error unless the second token sequence is identical to the first.

Microsoft Specific

Microsoft C/C++ allows the redefinition of a macro, but generates a warning, provided the new definition is lexically identical to a previous definition. ANSI C considers macro redefinition an error. For example, these macros are equivalent for C/C++ but generate warnings:

#define test( f1, f2 ) ( f1 * f2 )
#define test( a1, a2 ) ( a1 * a2 )

END Microsoft Specific

This example illustrates the #define directive:

#define WIDTH       80
#define LENGTH      ( WIDTH + 10 )

The first statement defines the identifier WIDTH as the integer constant 80 and defines LENGTH in terms of WIDTH and the integer constant 10. Each occurrence of LENGTH is replaced by (WIDTH + 10). In turn, each occurrence of WIDTH + 10 is replaced by the expression (80 + 10). The parentheses around WIDTH + 10 are important because they control the interpretation in statements such as the following:

var = LENGTH * 20;

After the preprocessing stage the statement becomes:

var = ( 80 + 10 ) * 20;

which evaluates to 1800. Without parentheses, the result is:

var = 80 + 10 * 20;

which evaluates to 280.

Microsoft Specific

Defining macros and constants with the /D compiler option has the same effect as using a #define preprocessing directive at the beginning of your file. Up to 30 macros can be defined with the /D option.

END Microsoft Specific


The #error Directive

Error directives produce compiler-time error messages.

Syntax

#error token-string

The error messages include the argument token-string and are subject to macro expansion. These directives are most useful for detecting programmer inconsistencies and violation of constraints during preprocessing. The following example demonstrates error processing during preprocessing:

#if !defined(__cplusplus)
#error C++ compiler required.
#endif

When #error directives are encountered, compilation terminates.


The #if, #elif, #else, and #endif Directives

The #if directive, with the #elif, #else, and #endif directives, controls compilation of portions of a source file. If the expression you write (after the #if) has a nonzero value, the line group immediately following the #if directive is retained in the translation unit.

Syntax

conditional :

if-part elif-partsopt else-partopt endif-line

if-part :

if-line text

if-line :

#if constant-expression
#ifdef identifier
#ifndef identifier

elif-parts :

elif-line text
elif-parts elif-line text

elif-line :

#elif constant-expression

else-part :

else-line text

else-line :

#else

endif-line :

#endif

Each #if directive in a source file must be matched by a closing #endif directive. Any number of #elif directives can appear between the #if and #endif directives, but at most one #else directive is allowed. The #else directive, if present, must be the last directive before #endif.

The #if, #elif, #else, and #endif directives can nest in the text portions of other #if directives. Each nested #else, #elif, or #endif directive belongs to the closest preceding #if directive.

All conditional-compilation directives, such as #if and #ifdef, must be matched with closing #endif directives prior to the end of file; otherwise, an error message is generated. When conditional-compilation directives are contained in include files, they must satisfy the same conditions: There must be no unmatched conditional-compilation directives at the end of the include file.

Macro replacement is performed within the part of the command line that follows an #elif command, so a macro call can be used in the constant-expression.

The preprocessor selects one of the given occurrences of text for further processing. A block specified in text can be any sequence of text. It can occupy more than one line. Usually text is program text that has meaning to the compiler or the preprocessor.

The preprocessor processes the selected text and passes it to the compiler. If text contains preprocessor directives, the preprocessor carries out those directives. Only text blocks selected by the preprocessor are compiled.

The preprocessor selects a single text item by evaluating the constant expression following each #if or #elif directive until it finds a true (nonzero) constant expression. It selects all text (including other preprocessor directives beginning with #) up to its associated #elif, #else, or #endif.

If all occurrences of constant-expression are false, or if no #elif directives appear, the preprocessor selects the text block after the #else clause. If the #else clause is omitted and all instances of constant-expression in the #if block are false, no text block is selected.

The constant-expression is an integer constant expression with these additional restrictions:

  • Expressions must have integral type and can include only integer constants, character constants, and the defined operator.

  • The expression cannot use sizeof or a type-cast operator.

  • The target environment may not be able to represent all ranges of integers.

  • The translation represents type int the same as type long, and unsigned int the same as unsigned long.

  • The translator can translate character constants to a set of code values different from the set for the target environment. To determine the properties of the target environment, check values of macros from LIMITS.H in an application built for the target environment.

  • The expression must not perform any environmental inquiries and must remain insulated from implementation details on the target computer.

The preprocessor operator defined can be used in special constant expressions, as shown by the following syntax:

Syntax

defined( identifier )

defined identifier

This constant expression is considered true (nonzero) if the identifier is currently defined; otherwise, the condition is false (0). An identifier defined as empty text is considered defined. The defined directive can be used in an #if and an #elif directive, but nowhere else.

In the following example, the #if and #endif directives control compilation of one of three function calls:

#if defined(CREDIT)
    credit();
#elif defined(DEBIT)
    debit();
#else
    printerror();
#endif

The function call to credit is compiled if the identifier CREDIT is defined. If the identifier DEBIT is defined, the function call to debit is compiled. If neither identifier is defined, the call to printerror is compiled. Note that CREDIT and credit are distinct identifiers in C and C++ because their cases are different.

The conditional compilation statements in the following example assume a previously defined symbolic constant named DLEVEL.

#if DLEVEL > 5
    #define SIGNAL  1
    #if STACKUSE == 1
        #define STACK   200
    #else
        #define STACK   100
    #endif
#else
    #define SIGNAL  0
    #if STACKUSE == 1
        #define STACK   100
    #else
        #define STACK   50
    #endif
#endif
#if DLEVEL == 0
    #define STACK 0
#elif DLEVEL == 1
    #define STACK 100
#elif DLEVEL > 5
    display( debugptr );
#else
    #define STACK 200
#endif

The first #if block shows two sets of nested #if, #else, and #endif directives. The first set of directives is processed only if DLEVEL > 5 is true. Otherwise, the statements after #else are processed.

The #elif and #else directives in the second example are used to make one of four choices, based on the value of DLEVEL. The constant STACK is set to 0, 100, or 200, depending on the definition of DLEVEL. If DLEVEL is greater than 5, then the statement

#elif DLEVEL > 5
display(debugptr);

is compiled and STACK is not defined.

A common use for conditional compilation is to prevent multiple inclusions of the same header file. In C++, where classes are often defined in header files, constructs like the following can be used to prevent multiple definitions:

// EXAMPLE.H - Example header file

#if !defined( EXAMPLE_H )
#define EXAMPLE_H

class Example
{
...
};

#endif // !defined( EXAMPLE_H )

The preceding code checks to see if the symbolic constant EXAMPLE_H is defined. If so, the file has already been included and need not be reprocessed. If not, the constant EXAMPLE_H is defined to mark EXAMPLE.H as already processed.

Microsoft Specific

Conditional compilation expressions are treated as signed long values, and these expressions are evaluated using the same rules as expressions in C++. For example, this expression:

#if 0xFFFFFFFFL > 1UL

is true.

END Microsoft Specific


The #ifdef and #ifndef Directives

The #ifdef and #ifndef directives perform the same task as the #if directive when it is used with defined( identifier ).

Syntax

#ifdef identifier

#ifndef identifier

is equivalent to

#if defined identifier

#if !defined identifier

You can use the #ifdef and #ifndef directives anywhere #if can be used. The #ifdef identifier statement is equivalent to #if 1 when identifier has been defined, and it is equivalent to #if 0 when identifier has not been defined or has been undefined with the #undef directive. These directives check only for the presence or absence of identifiers defined with #define, not for identifiers declared in the C or C++ source code.

These directives are provided only for compatibility with previous versions of the language. The defined( identifier ) constant expression used with the #if directive is preferred.

The #ifndef directive checks for the opposite of the condition checked by #ifdef. If the identifier has not been defined (or its definition has been removed with #undef), the condition is true (nonzero). Otherwise, the condition is false (0).

Microsoft Specific

The identifier can be passed from the command line using the /D option. Up to 30 macros can be specified with /D.

This is useful for checking whether a definition exists, because a definition can be passed from the command line. For example:

// PROG.CPP
#ifndef test    // These three statements go in your source code.
#define final
#endif

CL /Dtest prog.cpp // This is the command for compilation.

END Microsoft Specific


The #import Directive

C++ Specific

The #import directive is used to incorporate information from a type library. The content of the type library is converted into C++ classes, mostly describing the COM interfaces.

Syntax

#import "filename" [attributes]

#import <filename> [attributes]

attributes:

attribute1, attribute2, ...

attribute1 attribute2 ...

filename is the name of the file containing the type library information. A file can be one of the following types:

  • a type library (.TLB or .ODL) file

  • an executable (.EXE) file

  • a library (.DLL) file containing a type library resource (such as .OCX)

  • a compound document holding a type library

  • any other file format that can be understood by the LoadTypeLib API

The filename is optionally preceded by a directory specification. The filename must name an existing file. The difference between the two forms is the order in which the preprocessor searches for the type library files when the path is incompletely specified.

Syntax Form | Action
Quoted form | This form instructs the preprocessor to first look for type library files in the same directory of the file that contains the #import statement, and then in the directories of whatever files that include (#include) that file. The preprocessor then searches along the paths shown below.
Angle-bracket form | This form instructs the preprocessor to search for type library files along the paths shown below.

The compiler will search in the following directories for the named file:

  1. the PATH environment variable path list

  2. the LIB environment variable path list

  3. the path specified by the /I (additional include directories) compiler option

#import can optionally include one or more attributes. These attributes tell the compiler to modify the contents of the type-library headers. A backslash (\) symbol can be used to include additional lines in a single #import statement. For example:

#import “test.lib” no_namespace \
   rename(“OldName”, “NewName”)

The #import attributes are listed below:

exclude | high_method_prefix
high_property_prefixes | implementation_only
include(…) | inject_statement
named_guids | no_auto_exclude
no_implementation | no_namespace
raw_dispinterfaces | raw_interfaces_only
raw_method_prefix | raw_native_types
raw_property_prefixes | rename
rename_namespace |

#import creates two header files that reconstruct the type library contents in C++ source code. The primary header file is similar to that produced by the Microsoft Interface Definition Language (MIDL) compiler, but with additional compiler-generated code and data. The primary header file has the same base name as the type library, plus a .TLH extension. The secondary header file has the same base name as the type library, with a .TLI extension. It contains the implementations for compiler-generated member functions, and is included (#include) in the primary header file.

Both header files are placed in the output directory specified by the /Fo (name object file) option. They are then read and compiled by the compiler as if the primary header file was named by a #include directive.

The following compiler optimizations come with the #import directive:

  • The header file, when created, is given the same timestamp as the type library.

  • When #import is processed, the compiler first checks if the header exists and is up to date. If yes, then it does not need to be recreated.

  • The compiler delays initializing the OLE subsystem until the first #import command is encountered.

The #import directive also participates in minimal rebuild and can be placed in a precompiled header file. See Creating Precompiled Header Files for more information.

The Primary Type Library Header File

The primary type library header file consists of seven sections:

  1. Heading boilerplate: Consists of comments, #include statement for COMDEF.H (which defines some standard macros used in the header), and other miscellaneous setup information.

  2. Forward references and typedefs: Consists of structure declarations such as struct IMyInterface, and typedefs for any TKIND_ALIAS items.

  3. Smart pointer declarations: The template class _com_ptr_t is a smart-pointer implementation that encapsulates interface pointers and eliminates the need to call AddRef, Release, QueryInterface functions. In addition, it hides the CoCreateInstance call in creating a new COM object. This section uses macro statement _COM_SMARTPTR_TYPEDEF to establish typedefs of COM interfaces to be template specializations of the _com_ptr_t template class. For example, for interface IFoo, the .TLH file will contain:

    _COM_SMARTPTR_TYPEDEF(IFoo, __uuidof(IFoo));

    which the compiler will expand to:

    typedef _com_ptr_t<_com_IIID<IFoo, __uuidof(IFoo)> > IFooPtr;

    Type IFooPtr can then be used in place of the raw interface pointer IFoo*. Consequently, there is no need to call the various IUnknown member functions.

  4. Typeinfo declarations: Primarily consists of class definitions and other items exposing the individual typeinfo items returned by ITypeLib:GetTypeInfo. In this section, each typeinfo from the type library is reflected in the header in a form dependent on the TYPEKIND information.

  5. Optional old-style GUID definition: Contains initializations of the named GUID constants. These are names of the form CLSID_CoClass and IID_Interface, similar to those generated by the MIDL compiler.

  6. #include statement for the secondary type library header.

  7. Footer boilerplate: Currently includes #pragma pack(pop).

All sections, except the heading boilerplate and footer boilerplate section, are enclosed in a namespace with its name specified by the library statement in the original IDL file. You can use the names from the type library header either by an explicit qualification with the namespace name or by including the following statement:

using namespace MyLib;

immediately after the #import statement in the source code.

The namespace can be suppressed by using the no_namespace attribute of the #import directive. However, suppressing the namespace may lead to name collisions. The namespace can also be renamed by the rename_namespace attribute.

The compiler provides the full path to any type library dependency required by the type library it is currently processing. The path is written, in the form of comments, into the type library header (.TLH) that the compiler generates for each processed type library.

If a type library includes references to types defined in other type libraries, then the .TLH file will include comments of the following sort:

//
// Cross-referenced type libraries:
//
//  #import "c:\path\typelib0.tlb"
//

The actual filename in the #import comment is the full path of the cross-referenced type library, as stored in the registry. If you encounter errors that are due to missing type definitions, check the comments at the head of the .TLH to see which dependent type libraries may need to be imported first. Likely errors are syntax errors (e.g. C2143, C2146, C2321), C2501 (missing decl-specifiers), or C2433 ('inline' not permitted on data declaration) while compiling the .TLI file.

You must determine which of the dependency comments are not otherwise provided for by system headers and then provide an #import directive at some point before the #import directive of the dependent type library in order to resolve the errors.

The exclude attribute

exclude("Name1"[, "Name2",...])

Name1

First item to be excluded

Name2

Second item to be excluded (if necessary)

Type libraries may include definitions of items defined in system headers or other type libraries. This attribute can be used to exclude these items from the type library header files being generated. This attribute can take any number of arguments, each being a top-level type library item to be excluded.

The high_method_prefix attribute

high_method_prefix("Prefix")

Prefix

Prefix to be used

By default, high-level error-handling properties and methods are exposed by member functions named without a prefix. The names are from the type library. The high_method_prefix attribute is used to specify a prefix to be used in naming these high-level properties and methods.

The high_property_prefixes attribute

high_property_prefixes("GetPrefix","PutPrefix","PutRefPrefix")

GetPrefix

Prefix to be used for the propget methods

PutPrefix

Prefix to be used for the propput methods

PutRefPrefix

Prefix to be used for the propputref methods

By default, high-level error-handling propget, propput, and propputref methods are exposed by member functions named with prefixes Get, Put, and PutRef respectively. The high_property_prefixes attribute is used to specify alternate prefixes for all three property methods.

The implementation_only attribute

The implementation_only attribute suppresses the generation of the .TLH header file (the primary header file). This file contains all the declarations used to expose the type-library contents. The .TLI header file, with the implementations of the wrapper member functions, will be generated and included in the compilation.

When this attribute is specified, the content of the .TLI header is in the same namespace as the one normally used in the .TLH header. In addition, the member functions are not declared as inline.

The implementation_only attribute is intended for use in conjunction with the no_implementation attribute as a way of keeping the implementations out of the precompiled header (PCH) file. An #import statement with the no_implementation attribute is placed in the source region used to create the PCH. The resulting PCH is used by a number of source files. An #import statement with the implementation_only attribute is then used outside the PCH region. You are required to use this statement only once in one of the source files. This will generate all the required wrapper member functions without additional recompilation for each source file.

Note The implementation_only attribute in one #import statement must be use in conjunction with another #import statement, of the same type library, with the no_implementation attribute. Otherwise, compiler errors will be generated. This is because wrapper class definitions generated by the #import statement with the no_implementation attribute are required to compile the implementations generated by the implementation_only attribute.

The include(...) attribute

include(Name1[, Name2, ...])

Name1

First item to be forcibly included

Name2

Second item to be forcibly included (if necessary)

Type libraries may include definitions of items defined in system headers or other type libraries. #import attempts to avoid multiple definition errors by automatically excluding such items. If items have been excluded, as indicated by warning C4192, and they should not have been, this attribute can be used to disable the automatic exclusion. This attribute can take any number of arguments, each being the name of the type-library item to be included.

The inject_statement attribute

inject_statement("source_text")

source_text

Source text to be inserted into the type library header file

The inject_statement attribute inserts its argument as source text into the type-library header. The text is placed at the beginning of the namespace declaration that wraps the type-library contents in the header file.

The named_guids attribute

The named_guids attribute tells the compiler to define and initialize GUID variables in old style, of the form LIBID_MyLib, CLSID_MyCoClass, IID_MyInterface, and DIID_MyDispInterface.

The no_implementation attribute

The no_implementation attribute suppresses the generation of the .TLI header, which contains the implementations of the wrapper member functions. If this attribute is specified, the .TLH header, with the declarations to expose type-library items, will be generated without an #include statement to include the .TLI header file.

This attribute is used in conjunction with implementation_only.

The no_auto_exclude attribute

Type libraries may include definitions of items defined in system headers or other type libraries. #import attempts to avoid multiple definition errors by automatically excluding such items. When this is done, warning C4192 will be issued for each item to be excluded. You can disable this automatic exclusion by using this attribute.

The no_namespace attribute

The type-library contents in the #import header file are normally defined in a namespace. The namespace name is specified in the library statement of the original IDL file. If the no_namespace attribute is specified, this namespace is not generated by the compiler.

If you want to use a different namespace name, use the rename_namespace attribute instead.

The raw_dispinterfaces attribute

The raw_dispinterfaces attribute tells the compiler to generate low-level wrapper functions for dispinterface methods and properties that call IDispatch::Invoke and return the HRESULT error code.

If this attribute is not specified, only high-level wrappers are generated, which throw C++ exceptions in case of failure.

The raw_interfaces_only attribute

The raw_interfaces_only attribute suppresses the generation of error-handling wrapper functions and __declspec(property) declarations that use those wrapper functions.

The raw_interfaces_only attribute also causes the default prefix used in naming the non-property functions to be removed. Normally, the prefix is raw_. If this attribute is specified, the function names are directly from the type library.

This attribute allows you to expose only the low-level contents of the type library.

The raw_method_prefix attribute

raw_method_prefix("Prefix")

Prefix

The prefix to be used

Low-level properties and methods are exposed by member functions named with a default prefix of raw_ to avoid name collisions with the high-level error-handling member functions. The raw_method_prefix attribute is used to specify a different prefix.

Note The effects of the raw_method_prefix attribute will not be changed by the presence of the raw_interfaces_only attribute. The raw_method_prefix always takes precedence over raw_interfaces_only in specifying a prefix. If both attributes are used in the same #import statement, then the prefix specified by the raw_method_prefix attribute is used.

The raw_native_types attribute

By default, the high-level error-handling methods use the COM support classes _bstr_t and _variant_t in place of the BSTR and VARIANT data types and raw COM interface pointers. These classes encapsulate the details of allocating and deallocating memory storage for these data types, and greatly simplify type casting and conversion operations. The raw_native_types attribute is used to disable the use of these COM support classes in the high-level wrapper functions, and force the use of low-level data types instead.

The raw_property_prefixes attribute

raw_property_prefixes("GetPrefix","PutPrefix","PutRefPrefix")

GetPrefix

Prefix to be used for the propget methods

PutPrefix

Prefix to be used for the propput methods

PutRefPrefix

Prefix to be used for the propputref methods

By default, low-level propget, propput, and propputref methods are exposed by member functions named with prefixes of get_, put_, and putref_ respectively. These prefixes are compatible with the names used in the header files generated by MIDL. The raw_property_prefixes attribute is used to specify alternate prefixes for all three property methods.

The rename attribute

rename("OldName","NewName")

OldName

Old name in the type library

NewName

Name to be used instead of the old name

The rename attribute is used to work around name collision problems. If this attribute is specified, the compiler replaces all occurrences of OldName in a type library with the user-supplied NewName in the resulting header files.

This attribute can be used when a name in the type library coincides with a macro definition in the system header files. If this situation is not resolved, then various syntax errors will be generated, such as C2059 and C2061.

Note The replacement is for a name used in the type library, not for a name used in the resulting header file.

Here is an example: Suppose a property named MyParent exists in a type library, and a macro GetMyParent is defined in a header file and used before #import. Since GetMyParent is the default name of a wrapper function for the error-handling get property, a name collision will occur. To work around the problem, use the following attribute in the #import statement:

rename(“MyParent”,”MyParentX”)

which renames the name MyParent in the type library. An attempt to rename the GetMyParent wrapper name will fail:

rename(“GetMyParent”,”GetMyParentX”)

This is because the name GetMyParent only occurs in the resulting type library header file.

The rename_namespace attribute

rename_namespace("NewName")

NewName

The new name of the namespace

The rename_namespace attribute is used to rename the namespace that contains the contents of the type library. It takes a single argument, NewName, which specifies the new name for the namespace.

To remove the namespace, use the no_namespace attribute instead.

END C++ Specific


The #include Directive

The #include directive tells the preprocessor to treat the contents of a specified file as if those contents had appeared in the source program at the point where the directive appears. You can organize constant and macro definitions into include files and then use #include directives to add these definitions to any source file. Include files are also useful for incorporating declarations of external variables and complex data types. You only need to define and name the types once in an include file created for that purpose.

Syntax

#include "path-spec"

#include <path-spec>

The path-spec is a filename optionally preceded by a directory specification. The filename must name an existing file. The syntax of the path-spec depends on the operating system on which the program is compiled.

Both syntax forms cause replacement of that directive by the entire contents of the specified include file. The difference between the two forms is the order in which the preprocessor searches for header files when the path is incompletely specified.

Syntax Form | Action
Quoted form | This form instructs the preprocessor to look for include files in the same directory of the file that contains the #include statement, and then in the directories of whatever files that include (#include) that file. The preprocessor then searches along the path specified by the /I compiler option, then along paths specified by the INCLUDE environment variable.
Angle-bracket form | This form instructs the preprocessor to search for include files first along the path specified by the /I compiler option, then along the path specified by the INCLUDE environment variable.

The preprocessor stops searching as soon as it finds a file with the given name. If you specify a complete, unambiguous path specification for the include file between two sets of double quotation marks (" "), the preprocessor searches only that path specification and ignores the standard directories.

If the filename enclosed in double quotation marks is an incomplete path specification, the preprocessor first searches the “parent” file’s directory. A parent file is the file containing the #include directive. For example, if you include a file named file2 within a file named file1, file1 is the parent file.

Include files can be “nested”; that is, an #include directive can appear in a file named by another #include directive. For example, file2, above, could include file3. In this case, file1 would still be the parent of file2 but would be the “grandparent” of file3.

When include files are nested, directory searching begins with the directories of the parent file and then proceeds through the directories of any grandparent files. Thus, searching begins relative to the directory containing the source currently being processed. If the file is not found, the search moves to directories specified by the /I compiler option. Finally, the directories specified by the INCLUDE environment variable are searched.

The following example shows file inclusion using angle brackets:

#include <stdio.h>

This example adds the contents of the file named STDIO.H to the source program. The angle brackets cause the preprocessor to search the directories specified by the INCLUDE environment variable for STDIO.H, after searching directories specified by the /I compiler option.

The following example shows file inclusion using the quoted form:

#include "defs.h"

This example adds the contents of the file specified by DEFS.H to the source program. The double quotation marks mean that the preprocessor searches the directory containing the parent source file first.

Nesting of include files can continue up to 10 levels. Once the nested #include is processed, the preprocessor continues to insert the enclosing include file into the original source file.

Microsoft Specific

To locate includable source files, the preprocessor first searches the directories specified by the /I compiler option. If the /I option is not present or fails, the preprocessor uses the INCLUDE environment variable to find any include files within angle brackets. The INCLUDE environment variable and /I compiler option can contain multiple paths separated by semicolons (;). If more than one directory appears as part of the /I option or within the INCLUDE environment variable, the preprocessor searches them in the order in which they appear.

For example, the command

CL /ID:\MSVC\INCLUDE MYPROG.C

causes the preprocessor to search the directory D:\MSVC\INCLUDE for include files such as STDIO.H. The commands

SET INCLUDE=D:\MSVC\INCLUDE
CL MYPROG.C

have the same effect. If both sets of searches fail, a fatal compiler error is generated.

If the filename is fully specified for an include file with a path that includes a colon (for example, F:\MSVC\SPECIAL\INCL\TEST.H), the preprocessor follows the path.

For include files specified as #include "path-spec", directory searching begins with the directory of the parent file and then proceeds through the directories of any grandparent files. Thus, searching begins relative to the directory containing the source file containing the #include directive being processed. If there is no grandparent file and the file has not been found, the search continues as if the filename were enclosed in angle brackets.

END Microsoft Specific


The #line Directive

The #line directive tells the preprocessor to change the compiler’s internally stored line number and filename to a given line number and filename. The compiler uses the line number and filename to refer to errors that it finds during compilation. The line number usually refers to the current input line, and the filename refers to the current input file. The line number is incremented after each line is processed.

Syntax

#line

digit-sequence "filename"opt

The digit-sequence value can be any integer constant. Macro replacement can be performed on the preprocessing tokens, but the result must evaluate to the correct syntax. The filename can be any combination of characters and must be enclosed in double quotation marks (" "). If filename is omitted, the previous filename remains unchanged.

You can alter the source line number and filename by writing a #line directive. The translator uses the line number and filename to determine the values of the predefined macros __FILE__ and __LINE__. You can use these macros to insert self-descriptive error messages into the program text. For more information on these predefined macros, see Predefined Macros.

The __FILE__ macro expands to a string whose contents are the filename, surrounded by double quotation marks (" ").

If you change the line number and filename, the compiler ignores the previous values and continues processing with the new values. The #line directive is typically used by program generators to cause error messages to refer to the original source file instead of to the generated program.

The following examples illustrate #line and the __LINE__ and __FILE__ macros.

In this statement, the internally stored line number is set to 151 and the filename is changed to copy.c.

#line 151 "copy.c"

In this example, the macro ASSERT uses the predefined macros __LINE__ and __FILE__ to print an error message about the source file if a given “assertion” is not true.

#define ASSERT(cond)

if( !(cond) )\
{printf( "assertion error line %d, file(%s)\n", \
__LINE__, __FILE__ );}


The Null Directive

The null preprocessor directive is a single number sign (#) alone on a line. It has no effect.

Syntax

#


The #undef Directive

As its name implies, the #undef directive removes (undefines) a name previously created with #define.

Syntax

#undef

identifier

The #undef directive removes the current definition of identifier. Consequently, subsequent occurrences of identifier are ignored by the preprocessor. To remove a macro definition using #undef, give only the macro identifier ; do not give a parameter list.

You can also apply the #undef directive to an identifier that has no previous definition. This ensures that the identifier is undefined. Macro replacement is not performed within #undef statements.

The #undef directive is typically paired with a #define directive to create a region in a source program in which an identifier has a special meaning. For example, a specific function of the source program can use manifest constants to define environment-specific values that do not affect the rest of the program. The #undef directive also works with the #if directive to control conditional compilation of the source program. See The #if, #elif, #else, and #endif Directives for more information.

In the following example, the #undef directive removes definitions of a symbolic constant and a macro. Note that only the identifier of the macro is given.

#define WIDTH           80
#define ADD( X, Y )     (X) + (Y)
.
.
.
#undef WIDTH
#undef ADD

Microsoft Specific

Macros can be undefined from the command line using the /U option, followed by the macro names to be undefined. The effect of issuing this command is equivalent to a sequence of #undef macro-name statements at the beginning of the file.

END Microsoft Specific


Preprocessor Operators

Four preprocessor-specific operators are used in the context of the #define directive (see the following list for a summary of each). The stringizing, charizing, and token-pasting operators are discussed in the next three sections. For information on the defined operator, see The #if, #elif, #else, and #endif Directives.

Operator | Action
Stringizing operator (#) | Causes the corresponding actual argument to be enclosed in double quotation marks
Charizing operator (#@) | Causes the corresponding argument to be enclosed in single quotation marks and to be treated as a character (Microsoft Specific)
Token-pasting operator (##) | Allows tokens used as actual arguments to be concatenated to form other tokens
defined operator | Simplifies the writing of compound expressions in certain macro directives


Stringizing Operator (#)

The number-sign or “stringizing” operator (#) converts macro parameters (after expansion) to string constants. It is used only with macros that take arguments. If it precedes a formal parameter in the macro definition, the actual argument passed by the macro invocation is enclosed in quotation marks and treated as a string literal. The string literal then replaces each occurrence of a combination of the stringizing operator and formal parameter within the macro definition.

White space preceding the first token of the actual argument and following the last token of the actual argument is ignored. Any white space between the tokens in the actual argument is reduced to a single white space in the resulting string literal. Thus, if a comment occurs between two tokens in the actual argument, it is reduced to a single white space. The resulting string literal is automatically concatenated with any adjacent string literals from which it is separated only by white space.

Further, if a character contained in the argument usually requires an escape sequence when used in a string literal (for example, the quotation mark (") or backslash (\) character), the necessary escape backslash is automatically inserted before the character. The following example shows a macro definition that includes the stringizing operator and a main function that invokes the macro:

#define stringer( x ) printf( #x "\n" )

void main()
{
    stringer( In quotes in the printf function call\n );
    stringer( "In quotes when printed to the screen"\n );
    stringer( "This: \"  prints an escaped double quote" );
}

Such invocations would be expanded during preprocessing, producing the following code:

void main()
{
   printf( "In quotes in the printf function call\n" "\n" );
   printf( "\"In quotes when printed to the screen\"\n" "\n" );
   printf( "\"This: \\\" prints an escaped double quote\"" "\n" );
}

When the program is run, screen output for each line is as follows:

In quotes in the printf function call

"In quotes when printed to the screen"

"This: \" prints an escaped double quotation mark"

Microsoft Specific

The Microsoft C (versions 6.0 and earlier) extension to the ANSI C standard that previously expanded macro formal arguments appearing inside string literals and character constants is no longer supported. Code that relied on this extension should be rewritten using the stringizing (#) operator.

END Microsoft Specific


Charizing Operator (#@)

Microsoft Specific

The charizing operator can be used only with arguments of macros. If #@ precedes a formal parameter in the definition of the macro, the actual argument is enclosed in single quotation marks and treated as a character when the macro is expanded. For example:

#define makechar(x)  #@x

causes the statement

a = makechar(b);

to be expanded to

a = 'b';

The single-quotation character cannot be used with the charizing operator.

END Microsoft Specific


Token-Pasting Operator (##)

The double-number-sign or “token-pasting” operator (##), which is sometimes called the “merging” operator, is used in both object-like and function-like macros. It permits separate tokens to be joined into a single token and therefore cannot be the first or last token in the macro definition.

If a formal parameter in a macro definition is preceded or followed by the token-pasting operator, the formal parameter is immediately replaced by the unexpanded actual argument. Macro expansion is not performed on the argument prior to replacement.

Then, each occurrence of the token-pasting operator in token-string is removed, and the tokens preceding and following it are concatenated. The resulting token must be a valid token. If it is, the token is scanned for possible replacement if it represents a macro name. The identifier represents the name by which the concatenated tokens will be known in the program before replacement. Each token represents a token defined elsewhere, either within the program or on the compiler command line. White space preceding or following the operator is optional.

This example illustrates use of both the stringizing and token-pasting operators in specifying program output:

#define paster( n ) printf( "token" #n " = %d", token##n )
int token9 = 9;

If a macro is called with a numeric argument like

paster( 9 );

the macro yields

printf( "token" "9" " = %d", token9 );

which becomes

printf( "token9 = %d", token9 );


Macros

Preprocessing expands macros in all lines that are not preprocessor directives (lines that do not have a # as the first non-white-space character) and in parts of some directives that are not skipped as part of a conditional compilation. “Conditional compilation” directives allow you to suppress compilation of parts of a source file by testing a constant expression or identifier to determine which text blocks are passed on to the compiler and which text blocks are removed from the source file during preprocessing.

The #define directive is typically used to associate meaningful identifiers with constants, keywords, and commonly used statements or expressions. Identifiers that represent constants are sometimes called “symbolic constants” or “manifest constants.” Identifiers that represent statements or expressions are called “macros.” In this preprocessor documentation, only the term “macro” is used.

When the name of the macro is recognized in the program source text or in the arguments of certain other preprocessor commands, it is treated as a call to that macro. The macro name is replaced by a copy of the macro body. If the macro accepts arguments, the actual arguments following the macro name are substituted for formal parameters in the macro body. The process of replacing a macro call with the processed copy of the body is called “expansion” of the macro call.

In practical terms, there are two types of macros. “Object-like” macros take no arguments, whereas “function-like” macros can be defined to accept arguments so that they look and act like function calls. Because macros do not generate actual function calls, you can sometimes make programs run faster by replacing function calls with macros. (In C++, inline functions are often a preferred method.) However, macros can create problems if you do not define and use them with care. You may have to use parentheses in macro definitions with arguments to preserve the proper precedence in an expression. Also, macros may not correctly handle expressions with side effects. See the getrandom example in The #define Directive for more information.

Once you have defined a macro, you cannot redefine it to a different value without first removing the original definition. However, you can redefine the macro with exactly the same definition. Thus, the same definition can appear more than once in a program.

The #undef directive removes the definition of a macro. Once you have removed the definition, you can redefine the macro to a different value. The #define Directive and The #undef Directive discuss the #define and #undef directives, respectively.


Macros and C++

C++ offers new capabilities, some of which supplant those offered by the ANSI C preprocessor. These new capabilities enhance the type safety and predictability of the language:

  • In C++, objects declared as const can be used in constant expressions. This allows programs to declare constants that have type and value information, and enumerations that can be viewed symbolically with the debugger. Using the preprocessor #define directive to define constants is not as precise. No storage is allocated for a const object unless an expression that takes its address is found in the program.

  • The C++ inline function capability supplants function-type macros. The advantages of using inline functions over macros are:
    • Type safety. Inline functions are subject to the same type checking as normal functions. Macros are not type safe.

    • Correct handling of arguments that have side effects. Inline functions evaluate the expressions supplied as arguments prior to entering the function body. Therefore, there is no chance that an expression with side effects will be unsafe.

For more information on inline functions, see inline, __inline.

For backward compatibility, all preprocessor facilities that existed in ANSI C and in earlier C++ specifications are preserved for Microsoft C++.


Predefined Macros

The compiler recognizes six predefined ANSI C macros (see Table 1.1), and the Microsoft C++ implementation provides several more (see Table 1.2). These macros take no arguments and cannot be redefined. Their value (except for __LINE__ and __FILE__) must be constant throughout compilation. Some of the predefined macros listed below are defined with multiple values. Their values can be set by selecting the corresponding menu option in the Visual C++ development environment, or by using a command-line switch. See the tables below for more information.

Table 1.1 ANSI Predefined Macros

Macro | Description
__DATE__ | The compilation date of the current source file. The date is a string literal of the form Mmm dd yyyy. The month name Mmm is the same as for dates generated by the library function asctime declared in TIME.H.
__FILE__ | The name of the current source file. __FILE__ expands to a string surrounded by double quotation marks.
__LINE__ | The line number in the current source file. The line number is a decimal integer constant. It can be altered with a #line directive.
__STDC__ | Indicates full conformance with the ANSI C standard. Defined as the integer constant 1 only if the /Za compiler option is given and you are not compiling C++ code; otherwise is undefined.
__TIME__ | The most recent compilation time of the current source file. The time is a string literal of the form hh:mm:ss.
__TIMESTAMP__ | The date and time of the last modification of the current source file, expressed as a string literal in the form Ddd Mmm Date hh:mm:ss yyyy, where Ddd is the abbreviated day of the week and Date is an integer from 1 to 31.

Table 1.2 Microsoft-Specific Predefined Macros

Macro | Description
_CHAR_UNSIGNED | Default char type is unsigned. Defined when /J is specified.
__cplusplus | Defined for C++ programs only.
_CPPRTTI | Defined for code compiled with /GR (Enable Run-Time Type Information).
_CPPUNWIND | Defined for code compiled with /GX (Enable Exception Handling).
_DLL | Defined when /MD or /MDd (Multithread DLL) is specified.
_M_ALPHA | Defined for DEC ALPHA platforms. It is defined as 1 by the ALPHA compiler, and it is not defined if another compiler is used.
_M_IX86 | Defined for x86 processors. See Table 1.3 for more details.
_M_MPPC | Defined for Power Macintosh platforms. Default is 601 (/QP601). See Table 1.4 for more details.
_M_MRX000 | Defined for MIPS platforms. Default is 4000 (/QMR4000). See Table 1.5 for more details.
_M_PPC | Defined for PowerPC platforms. Default is 604 (/QP604). See Table 1.6 for more details.
_MFC_VER | Defines the MFC version. Defined as 0x0421 for Microsoft Foundation Class Library 4.21. Always defined.
_MSC_EXTENSIONS | This macro is defined when compiling with the /Ze compiler option (the default). Its value, when defined, is 1.
_MSC_VER | Defines the compiler version. Defined as 1200 for Microsoft Visual C++ 6.0. Always defined.
_MT | Defined when /MD or /MDd (Multithreaded DLL) or /MT or /MTd (Multithreaded) is specified.
_WIN32 | Defined for applications for Win32®. Always defined.

As shown in following tables, the compiler generates a value for the preprocessor identifiers that reflect the processor option specified.

Table 1.3 Values for _M_IX86

Option in Developer Studio | Command-Line Option | Resulting Value
Blend | /GB | _M_IX86 = 500 (Default. Future compilers will emit a different value to reflect the dominant processor.)
Pentium | /G5 | _M_IX86 = 500
Pentium Pro | /G6 | _M_IX86 = 600
80386 | /G3 | _M_IX86 = 300
80486 | /G4 | _M_IX86 = 400

Table 1.4 Values for _M_MPPC

Option in development environment | Command-Line Option | Resulting Value
PowerPC 601 | /QP601 | _M_MPPC = 601 (Default)
PowerPC 603 | /QP603 | _M_MPPC = 603
PowerPC 604 | /QP604 | _M_MPPC = 604
PowerPC 620 | /QP620 | _M_MPPC = 620

Table 1.5 Values for _M_MRX000

Option in Developer Studio | Command-Line Option | Resulting Value
R4000 | /QMR4000 | _M_MRX000 = 4000 (Default)
R4100 | /QMR4100 | _M_MRX000 = 4100
R4200 | /QMR4200 | _M_MRX000 = 4200
R4400 | /QMR4400 | _M_MRX000 = 4400
R4600 | /QMR4600 | _M_MRX000 = 4600
R10000 | /QMR10000 | _M_MRX000 = 10000

Table 1.6 Values for _M_PPC

Option in Developer Studio | Command-Line Option | Resulting Value
PowerPC 601 | /QP601 | _M_PPC = 601
PowerPC 603 | /QP603 | _M_PPC = 603
PowerPC 604 | /QP604 | _M_PPC = 604 (Default)
PowerPC 620 | /QP620 | _M_PPC = 620


Pragma Directives

Each implementation of C and C++ supports some features unique to its host machine or operating system. Some programs, for instance, need to exercise precise control over the memory areas where data is placed or to control the way certain functions receive parameters. The #pragma directives offer a way for each compiler to offer machine- and operating-system-specific features while retaining overall compatibility with the C and C++ languages. Pragmas are machine- or operating-system-specific by definition, and are usually different for every compiler.

Syntax

#pragma token-string

The token-string is a series of characters that gives a specific compiler instruction and arguments, if any. The number sign (#) must be the first non-white-space character on the line containing the pragma; white-space characters can separate the number sign and the word pragma. Following #pragma, write any text that the translator can parse as preprocessing tokens. The argument to #pragma is subject to macro expansion.

If the compiler finds a pragma it does not recognize, it issues a warning, but compilation continues.

Pragmas can be used in conditional statements, to provide new preprocessor functionality, or to provide implementation-defined information to the compiler. The C and C++ compilers recognize the following pragmas:

alloc_text | comment | init_seg 1 | optimize
auto_inline | component | inline_depth | pack
bss_seg | data_seg | inline_recursion | pointers_to_members 1
check_stack | function | intrinsic | setlocale
code_seg | hdrstop | message | vtordisp 1
const_seg | include_alias | once | warning

1. Supported only by the C++ compiler.


Pragmas Specific to the C++ Compiler

The following pragma directives are specific to the C++ compiler:

  • init_seg

  • pointers_to_members

  • vtordisp


init_seg

C++ Specific —>

#pragma init_seg({ compiler | lib | user | "section-name" [, "func-name"]} )

Specifies a keyword or code section that affects the order in which startup code is executed. Because initialization of global static objects can involve executing code, you must specify a keyword that defines when the objects are to be constructed. It is particularly important to use the init_seg pragma in dynamic-link libraries (DLLs) or libraries requiring initialization.

The options to the init_seg pragma are:

compiler

Reserved for Microsoft C run-time library initialization. Objects in this group are constructed first.

lib

Available for third-party class-library vendors’ initializations. Objects in this group are constructed after those marked as compiler but before any others.

user

Available to any user. Objects in this group are constructed last.

section-name

Allows explicit specification of the initialization section. Objects in a user-specified section-name are not implicitly constructed; however, their addresses are placed in the section named by section-name.

func-name

Specifies a function to be called in place of atexit when the program exits. The function specified must have the same signature as the atexit function:

int funcname(void (__cdecl *)(void));

If you need to defer initialization (for example, in a DLL), you may choose to specify the section name explicitly. You must then call the constructors for each static object.

END C++ Specific


pointers_to_members

C++ Specific —>

#pragma pointers_to_members(pointer-declaration, [most-general-representation] )

Specifies whether a pointer to a class member can be declared before its associated class definition and is used to control the pointer size and the code required to interpret the pointer. You can place a pointers_to_members pragma in your source file as an alternative to using the /vmx compiler options.

The pointer-declaration argument specifies whether you have declared a pointer to a member before or after the associated function definition. The pointer-declaration argument is one of the following two symbols:

Argument | Comments
full_generality | Generates safe, sometimes nonoptimal code. You use full_generality if any pointer to a member is declared before the associated class definition. This argument always uses the pointer representation specified by the most-general-representation argument. Equivalent to /vmg.
best_case | Generates safe, optimal code using best-case representation for all pointers to members. Requires defining the class before declaring a pointer to a member of the class. The default is best_case.

The most-general-representation argument specifies the smallest pointer representation that the compiler can safely use to reference any pointer to a member of a class in a translation unit. The argument can be one of the following:

Argument | Comments
single_inheritance | The most general representation is single-inheritance, pointer to a member function. Causes an error if the inheritance model of a class definition for which a pointer to a member is declared is ever either multiple or virtual.
multiple_inheritance | The most general representation is multiple-inheritance, pointer to a member function. Causes an error if the inheritance model of a class definition for which a pointer to a member is declared is virtual.
virtual_inheritance | The most general representation is virtual-inheritance, pointer to a member function. Never causes an error. This is the default argument when #pragma pointers_to_members(full_generality) is used.

END C++ Specific


vtordisp

C++ Specific —>

#pragma vtordisp({on | off} )

Enables the addition of the hidden vtordisp construction/destruction displacement member. The vtordisp pragma is applicable only to code that uses virtual bases. If a derived class overrides a virtual function that it inherits from a virtual base class, and if a constructor or destructor for the derived class calls that function using a pointer to the virtual base class, the compiler may introduce additional hidden “vtordisp” fields into classes with virtual bases.

The vtordisp pragma affects the layout of classes that follow it. The /vd0 and /vd1 options specify the same behavior for complete modules. Specifying off suppresses the hidden vtordisp members. Specifying on, the default, enables them where they are necessary. Turn off vtordisp only if there is no possibility that the class’s constructors and destructors call virtual functions on the object pointed to by the this pointer.\

#pragma vtordisp( off )
class GetReal : virtual public { ... };
#pragma vtordisp( on )

END C++ Specific


C and C++ Compiler Pragmas

The following pragmas are defined for both the C and C++ compilers:

alloc_text | component | init_seg 1 | optimize
auto_inline | const_seg | inline_depth | pack
bss_seg | data_seg | inline_recursion | pointers_to_members 1
check_stack | function | intrinsic | setlocale
code_seg | hdrstop | message | vtordisp 1
comment | include_alias | once | warning

1 Supported only by the C++ compiler.


alloc_text

#pragma alloc_text( "textsection", function1, ... )

Names the code section where the specified function definitions are to reside. The pragma must occur between a function declarator and the function definition for the named functions.

The alloc_text pragma does not handle C++ member functions or overloaded functions. It is applicable only to functions declared with C linkage — that is, functions declared with the extern "C" linkage specification. If you attempt to use this pragma on a function with C++ linkage, a compiler error is generated.

Since function addressing using __based is not supported, specifying section locations requires the use of the alloc_text pragma. The name specified by textsection should be enclosed in double quotation marks.

The alloc_text pragma must appear after the declarations of any of the specified functions and before the definitions of these functions.

Functions referenced in an alloc_text pragma should be defined in the same module as the pragma. If this is not done and an undefined function is later compiled into a different text section, the error may or may not be caught. Although the program will usually run correctly, the function will not be allocated in the intended sections.

Other limitations on alloc_text are as follows:

  • It cannot be used inside a function.

  • It must be used after the function has been declared, but before the function has been defined.


auto_inline

#pragma auto_inline( [{on | off}] )

Excludes any functions defined within the range where off is specified from being considered as candidates for automatic inline expansion. To use the auto_inline pragma, place it before and immediately after (not in) a function definition. The pragma takes effect at the first function definition after the pragma is seen. Pragma auto_inline does not apply to explicit inline functions.


bss_seg

#pragma data_seg( ["section-name"[, "section-class"] ] )

Specifies the default section for unitialized data. The data_seg pragma has the same effect but works with initialized or unitialized data. In some cases, you can use bss_seg to speed up your load time by putting all unitialized data in one section.

#pragma bss_seg( "MY_DATA" )

causes uninitialized data allocated following the #pragma statement to be placed in a section called MY_DATA.

Data allocated using the bss_seg pragma does not retain any information about its location.

The second parameter, section-class, is included for compatibilty with versions of Visual C++ prior to version 2.0, and is now ignored.


check_stack

#pragma check_stack([ {on | off}] )

#pragma check_stack{+ | –}

Instructs the compiler to turn off stack probes if off (or –) is specified, or to turn on stack probes if on (or +) is specified. If no argument is given, stack probes are treated according to the default. This pragma takes effect at the first function defined after the pragma is seen. Stack probes are not a part of macros nor of functions that are generated inline.

If you don’t give an argument for the check_stack pragma, stack checking reverts to the behavior specified on the command line. For more information, see Compiler Reference. The interaction of the #pragma check_stack and the /Gs option is summarized in Table 2.1.

Table 2.1 Using the check_stack Pragma

Syntax Compiled with
/Gs option? 		Action
#pragma check_stack( ) or
#pragma check_stack 		Yes Turns off stack checking for functions that follow
#pragma check_stack( ) or
#pragma check_stack 		No Turns on stack checking for functions that follow
#pragma check_stack(on) or
#pragma check_stack + 		Yes or no Turns on stack checking for functions that follow
#pragma check_stack(off) or
#pragma check_stack – 		Yes or no Turns off stack checking for functions that follow


code_seg

#pragma code_seg( ["section-name"[,"section-class"] ] )

Specifies a code section where functions are to be allocated. The code_seg pragma specifies the default section for functions. You can, optionally, specify the class as well as the section name. Using #pragma code_seg without a section-name string resets allocation to whatever it was when compilation began.


const_seg

#pragma const_seg( ["section-name"[, "section-class"] ] )

Specifies the default section for constant data. The data_seg pragma has the same effect but works with all data. You can use this pragma to put all your constant data in one read-only section.

#pragma const_seg( "MY_DATA" )

causes constant data allocated following the #pragma statement to be placed in a section called MY_DATA.

Data allocated using the const_seg pragma does not retain any information about its location.

The second parameter, section-class, is included for compatibilty with versions of Visual C++ prior to version 2.0, and is now ignored.


comment

#pragma comment( comment-type [, commentstring] )

Places a comment record into an object file or executable file. The comment-type is one of five predefined identifiers, described below, that specify the type of comment record. The optional commentstring is a string literal that provides additional information for some comment types. Because commentstring is a string literal, it obeys all the rules for string literals with respect to escape characters, embedded quotation marks ("), and concatenation.

compiler

Places the name and version number of the compiler in the object file. This comment record is ignored by the linker. If you supply a commentstring parameter for this record type, the compiler generates a warning.

exestr

Places commentstring in the object file. At link time, this string is placed in the executable file. The string is not loaded into memory when the executable file is loaded; however, it can be found with a program that finds printable strings in files. One use for this comment-record type is to embed a version number or similar information in an executable file.

lib

Places a library-search record in the object file. This comment type must be accompanied by a commentstring parameter containing the name (and possibly the path) of the library that you want the linker to search. Since the library name precedes the default library-search records in the object file, the linker searches for this library just as if you had named it on the command line. You can place multiple library-search records in the same source file; each record appears in the object file in the same order in which it is encountered in the source file.

linker

Places a linker option in the object file. You can use this comment-type to specify a linker option instead placing the option on the Link tab of the Project Settings dialog box. For example, you can specity the /include option to force the inclusion of a symbol:

#pragma comment(linker, "/include:__mySymbol")

user

Places a general comment in the object file. The commentstring parameter contains the text of the comment. This comment record is ignored by the linker.

The following pragma causes the linker to search for the EMAPI.LIB library while linking. The linker searches first in the current working directory and then in the path specified in the LIB environment variable.

#pragma comment( lib, "emapi" )

The following pragma causes the compiler to place the name and version number of the compiler in the object file:

#pragma comment( compiler )

Note For comments that take a commentstring parameter, you can use a macro in any place where you would use a string literal, provided that the macro expands to a string literal. You can also concatenate any combination of string literals and macros that expand to string literals. For example, the following statement is acceptable:

#pragma comment( user, "Compiled on " __DATE__ " at " __TIME__ )


component

#pragma component( browser, { on | off }[, references [, name ]] )

#pragma component( minrebuild, on | off )

Controls the collecting of browse information or dependency information from within source files.

Browser

You can turn collecting on or off, and you can specify particular names to be ignored as information is collected.

Using on or off controls the collection of browse information from the pragma forward. For example:

#pragma component(browser, off)

stops the compiler from collecting browse information.

Note To turn on the collecting of browse information with this pragma, browse information must first be enabled from the Project Settings dialog box or the command line.

The references option can be used with or without the name argument. Using references without name turns on or off the collecting of references (other browse information continues to be collected, however). For example:

#pragma component(browser, off, references)

stops the compiler from collecting reference information.

Using references with name and off prevents references to name from appearing in the browse information window. Use this syntax to ignore names and types you are not interested in and to reduce the size of browse information files. For example:

#pragma component(browser, off, references, DWORD)

ignores references to DWORD from that point forward. You can turn collecting of references to DWORD back on by using on:

#pragma component(browser, on, references, DWORD)

This is the only way to resume collecting references to name; you must explicitly turn on any name that you have turned off.

To prevent the preprocessor from expanding name (such as expanding NULL to 0), put quotes around it:

#pragma component(browser, off, references, "NULL")

Minimal Rebuild

The Visual C++ minimal rebuild feature requires that the compiler create and store C++ class dependency information, which takes disk space. To save disk space, you can use #pragma component( minrebuild, off ) whenever you don't need to collect dependency information, for instance, in unchanging header files. Insert #pragma component(minrebuild, on) after unchanging classes to turn dependency collection back on.

For more information, see the Enable Minimal Rebuild (/Gm) compiler option.


data_seg

#pragma data_seg( ["section-name"[, "section-class"] ] )

Specifies the default section for data. For example:

#pragma data_seg( "MY_DATA" )

causes data allocated following the #pragma statement to be placed in a section called MY_DATA.

Data allocated using the data_seg pragma does not retain any information about its location.

The second parameter, section-class, is included for compatibilty with versions of Visual C++ prior to version 2.0, and is now ignored.


function

#pragma function( function1 [, function2, ...] )

Specifies that calls to functions specified in the pragma’s argument list be generated. If you use the intrinsic pragma (or /Oi) to tell the compiler to generate intrinsic functions (intrinsic functions are generated as inline code, not as function calls), you can use the function pragma to explicitly force a function call. Once a function pragma is seen, it takes effect at the first function definition containing a specified intrinsic function. The effect continues to the end of the source file or to the appearance of an intrinsic pragma specifying the same intrinsic function. The function pragma can be used only outside of a function — at the global level.

For lists of the functions that have intrinsic forms, see #pragma intrinsic.


hdrstop

#pragma hdrstop [( "filename" )]

Controls the way precompiled headers work. The filename is the name of the precompiled header file to use or create (depending on whether /Yu or /Yc is specified). If filename does not contain a path specification, the precompiled header file is assumed to be in the same directory as the source file. Any filename is ignored when /YX, the automatic precompiled header option, is specified.

If a C or C++ file contains a hdrstop pragma when compiled with either /YX or /Yc, the compiler saves the state of the compilation up to the location of the pragma. The compiled state of any code that follows the pragma is not saved.

The hdrstop pragma cannot occur inside a header file. It must occur in the source file at the file level; that is, it cannot occur within any data or function declaration or definition.

Note The hdrstop pragma is ignored unless either the /YX option is specified or the /Yu or /Yc option is specified without a filename.

Use filename to name the precompiled header file in which the compiled state is saved. A space between hdrstop and filename is optional. The filename specified in the hdrstop pragma is a string and is therefore subject to the constraints of any C or C++ string. In particular, you must enclose it in quotation marks as shown in the following example:

#pragma hdrstop( "c:\projects\include\myinc.pch" )

The name of the precompiled header file is determined according to the following rules, in order of precedence:

  1. The argument to the /Fp compiler option

  2. The filename argument to #pragma hdrstop

  3. The base name of the source file with a .PCH extension


include_alias

#pragma include_alias( "long_filename", "short_filename" )

#pragma include_alias( <long_filename>, <short_filename> )

Specifies that short_filename is to be used as an alias for long_filename. Some file systems allow longer header filenames than the 8.3 FAT file system limit. The compiler cannot simply truncate the longer names to 8.3, because the first eight characters of the longer header filenames may not be unique. Whenever the compiler encounters the long_filename string, it substitutes short_filename, and looks for the header file short_filename instead. This pragma must appear before the corresponding #include directives. For example:

// First eight characters of these two files not unique.
#pragma include_alias( "AppleSystemHeaderQuickdraw.h", "quickdra.h" )
#pragma include_alias( "AppleSystemHeaderFruit.h", "fruit.h" )

#pragma include_alias( "GraphicsMenu.h", "gramenu.h" )

#include "AppleSystemHeaderQuickdraw.h"
#include "AppleSystemHeaderFruit.h"
#include "GraphicsMenu.h"

The alias being searched for must match the specification exactly, in case as well as in spelling and in use of double quotation marks or angle brackets. The include_alias pragma performs simple string matching on the filenames; no other filename validation is performed. For example, given the following directives,

#pragma include_alias("mymath.h", "math.h")
#include "./mymath.h"
#include "sys/mymath.h"

no aliasing (substitution) is performed, since the header file strings do not match exactly. Also, header filenames used as arguments to the /Yu, /Yc, and /YX compiler options, or the hdrstop pragma, are not substituted. For example, if your source file contains the following directive,

#include <AppleSystemHeaderStop.h>

the corresponding compiler option should be

/YcAppleSystemHeaderStop.h

You can use the include_alias pragma to map any header filename to another. For example:

#pragma include_alias( "api.h", "c:\version1.0\api.h" )
#pragma include_alias( <stdio.h>, <newstdio.h> )
#include "api.h"
#include <stdio.h>

Do not mix filenames enclosed in double quotation marks with filenames enclosed in angle brackets. For example, given the above two #pragma include_alias directives, the compiler performs no substitution on the following #include directives:

#include <api.h>
#include "stdio.h"

Furthermore, the following directive generates an error:

#pragma include_alias(<header.h>, "header.h")  // Error

Note that the filename reported in error messages, or as the value of the predefined __FILE__ macro, is the name of the file after the substitution has been performed. For example, after the following directives,

#pragma include_alias( "VeryLongFileName.H", "myfile.h" )
#include "VeryLongFileName.H"

an error in VERYLONGFILENAME.H produces the following error message:

myfile.h(15) : error C2059 : syntax error

Also note that transitivity is not supported. Given the following directives,

#pragma include_alias( "one.h", "two.h" )
#pragma include_alias( "two.h", "three.h" )
#include "one.h"

the compiler searches for the file TWO.H rather than THREE.H.


inline_depth

#pragma inline_depth( [0... 255] )

Controls the number of times inline expansion can occur by controlling the number of times that a series of function calls can be expanded (from 0 to 255 times). This pragma controls the inlining of functions marked inline and __inline or inlined automatically under the /Ob2 option.

The inline_depth pragma controls the number of times a series of function calls can be expanded. For example, if the inline depth is four, and if A calls B and B then calls C, all three calls will be expanded inline. However, if the closest inline expansion is two, only A and B are expanded, and C remains as a function call.

To use this pragma, you must set the /Ob compiler option to 1 or 2. The depth set using this pragma takes effect at the first function call after the pragma. If you do not specify a value within the parentheses, inline_depth sets the inline depth back to its default value of 8.

The inline depth can be decreased during expansion but not increased. If the inline depth is six and during expansion the preprocessor encounters an inline_depth pragma with a value of eight, the depth remains six.

An inline depth of 0 inhibits inline expansion; an inline depth of 255 places no limit on inline expansion. If either pragma is used without specifying a value, the default value is used.


inline_recursion

#pragma inline_recursion( [{on | off}] )

Controls the inline expansion of direct or mutually recursive function calls. Use this pragma to control functions marked as inline and __inline or functions that the compiler automatically expands under the /Ob2 option. Use of this pragma requires an /Ob compiler option setting of either 1 or 2. The default state for inline_recursion is off. This pragma takes effect at the first function call after the pragma is seen and does not affect the definition of the function.

The inline_recursion pragma controls how recursive functions are expanded. If inline_recursion is off, and if an inline function calls itself (either directly or indirectly), the function is expanded only once. If inline_recursion is on, the function is expanded multiple times until the value of inline_depth is reached or capacity limits are reached.


intrinsic

#pragma intrinsic( function1 [, function2, ...] )

Specifies that calls to functions specified in the pragma’s argument list are intrinsic. The compiler generates intrinsic functions as inline code, not as function calls. The library functions with intrinsic forms are listed below. Once an intrinsic pragma is seen, it takes effect at the first function definition containing a specified intrinsic function. The effect continues to the end of the source file or to the appearance of a function pragma specifying the same intrinsic function. The intrinsic pragma can be used only outside of a function definition — at the global level.

The following functions have intrinsic forms:

_disable

_enable

_inp

_inpw

_lrotl

_lrotr

 _outp

_outpw

_rotl

_rotr

_strset

abs

 fabs

labs

memcmp

memcpy

memset

strcat

 strcmp

strcpy

strlen

Programs that use intrinsic functions are faster because they do not have the overhead of function calls but may be larger due to the additional code generated.

Note The _alloca and setjmp functions are always generated inline; this behavior is not affected by the intrinsic pragma.

The floating-point functions listed below do not have true intrinsic forms. Instead they have versions that pass arguments directly to the floating-point chip rather than pushing them onto the program stack:

acos

asin

 cosh

fmod

 pow

sinh

 tanh

The floating-point functions listed below have true intrinsic forms when you specify both the /Oi and /Og compiler options (or any option that includes /Og: /Ox, /O1, and /O2):

atan | exp | log10 | sqrt
atan2 | log | sin | tan
cos |  |  |

You can use the /Op or /Za compiler option to override generation of true intrinsic floating-point options. In this case, the functions are generated as library routines that pass arguments directly to the floating-point chip instead of pushing them onto the program stack.


message

#pragma message( messagestring )

Sends a string literal to the standard output without terminating the compilation. A typical use of the message pragma is to display informational messages at compile time.

The following code fragment uses the message pragma to display a message during compilation:

#if _M_IX86 == 500
#pragma message( "Pentium processor build" )
#endif

The messagestring parameter can be a macro that expands to a string literal, and you can concatenate such macros with string literals in any combination. For example, the following statements display the name of the file being compiled and the date and time when the file was last modified:

#pragma message( "Compiling " __FILE__ )
#pragma message( "Last modified on " __TIMESTAMP__ )


once

#pragma once

Specifies that the file, in which the pragma resides, will be included (opened) only once by the compiler in a build. A common use for this pragma is the following:

//header.h
#pragma once
// Your C or C++ code would follow:


optimize

#pragma optimize( "[optimization-list]", {on | off} )

Feature Only in Professional and Enterprise Edition Code optimization is supported only in Visual C++ Professional and Enterprise Editions. For more information, see Visual C++ Editions.

Specifies optimizations to be performed on a function-by-function basis. The optimize pragma must appear outside a function and takes effect at the first function defined after the pragma is seen. The on and off arguments turn options specified in the optimization-list on or off.

The optimization-list can be zero or more of the parameters shown in Table 2.2.

Table 2.2 Parameters of the optimize Pragma

Parameter(s) | Type of optimization
a | Assume no aliasing.
g | Enable global optimizations.
p | Improve floating-point consistency.
s or t | Specify short or fast sequences of machine code.
w | Assume no aliasing across function calls.
y | Generate frame pointers on the program stack.

These are the same letters used with the /O compiler options. For example,

#pragma optimize( "atp", on )

Using the optimize pragma with the empty string (" ") is a special form of the directive. It either turns off all optimizations or restores them to their original (or default) settings.

#pragma optimize( "", off )
.
.
.
#pragma optimize( "", on )


pack

#pragma pack( [ n] )

Specifies packing alignment for structure and union members. Whereas the packing alignment of structures and unions is set for an entire translation unit by the /Zp option, the packing alignment is set at the data-declaration level by the pack pragma. The pragma takes effect at the first structure or union declaration after the pragma is seen; the pragma has no effect on definitions.

When you use #pragma pack(n), where n is 1, 2, 4, 8, or 16, each structure member after the first is stored on the smaller member type or n-byte boundaries. If you use #pragma pack without an argument, structure members are packed to the value specified by /Zp. The default /Zp packing size is /Zp8.

The compiler also supports the following enhanced syntax:

#pragma pack( [ [ { push | pop}, ] [ identifier, ] ] [ n ] )

This syntax allows you to combine program components into a single translation unit if the different components use pack pragmas to specify different packing alignments.

Each occurrence of a pack pragma with a push argument stores the current packing alignment on an internal compiler stack. The pragma’s argument list is read from left to right. If you use push, the current packing value is stored. If you provide a value for n, that value becomes the new packing value. If you specify an identifier, a name of your choosing, the identifier is associated with the new packing value.

Each occurrence of a pack pragma with a pop argument retrieves the value at the top of an internal compiler stack and makes that value the new packing alignment. If you use pop and the internal compiler stack is empty, the alignment value is that set from the command-line and a warning is issued. If you use pop and specify a value for n, that value becomes the new packing value. If you use pop and specify an identifier, all values stored on the stack are removed from the stack until a matching identifier is found. The packing value associated with the identifier is also removed from the stack and the packing value that existed just before the identifier was pushed becomes the new packing value. If no matching identifier is found, the packing value set from the command line is used and a level-one warning is issued. The default packing alignment is 8.

The new, enhanced functionality of the pack pragma allows you to write header files that ensure that packing values are the same before and after the header file is encountered:

/* File name: include1.h
*/
#pragma pack( push, enter_include1 )
/* Your include-file code ... */
#pragma pack( pop, enter_include1 )
/* End of include1.h */

In the previous example, the current pack value is associated with the identifier enter_include1 and pushed, remembered, on entry to the header file. The pack pragma at the end of the header file removes all intervening pack values that may have occurred in the header file and removes the pack value associated with enter_include1. The header file thus ensures that the pack value is the same before and after the header file.

The new functionality also allows you to use code, such as header files, that uses pack pragmas to set packing alignments that differ from the packing value set in your code:

#pragma pack( push, before_include1 )
#include "include1.h"
#pragma pack( pop, before_include1 )

In the previous example, your code is protected from any changes to the packing value that might occur in include.h.


setlocale

#pragma setlocale( "locale-string" )

Defines the locale (country and language) to be used when translating wide-character constants and string literals. Since the algorithm for converting multibyte characters to wide characters may vary by locale or the compilation may take place in a different locale from where an executable file will be run, this pragma provides a way to specify the target locale at compile time. This guarantees that the wide-character strings will be stored in the correct format. The default locale-string is "C". The "C" locale maps each character in the string to its value as a wchar_t (unsigned short).


warning

#pragma warning( warning-specifier : warning-number-list [,warning-specifier : warning-number-list...] )

#pragma warning( push[ , n ] )

#pragma warning( pop )

Allows selective modification of the behavior of compiler warning messages.

The warning-specifier can be one of the following.

Warning-specifier | Meaning
once | Display the specified message(s) only once.
default | Apply the default compiler behavior to the specified message(s).
1, 2, 3, 4 | Apply the given warning level to the specified warning message(s).
disable | Do not issue the specified warning message(s).
error | Report the specified warnings as errors.

The warning-number-list can contain any warning numbers. Multiple options can be specified in the same pragma directive as follows:

#pragma warning( disable : 4507 34; once : 4385; error : 164 )

This is functionally equivalent to:

#pragma warning( disable : 4507 34 )  // Disable warning messages
                                      //  4507 and 34.
#pragma warning( once : 4385 )        // Issue warning 4385
                                      //  only once.
#pragma warning( error : 164 )        // Report warning 164
                                      //  as an error.

For warning numbers greater than 4699, those associated with code generation, the warning pragma has effect only when placed outside function definitions. The pragma is ignored if it specifies a number greater than 4699 and is used inside a function. The following example illustrates the correct placement of warning pragmas to disable, and then restore, the generation of a code-generation warning message:

int a;
#pragma warning( disable : 4705 )
void func()
{
    a;
}
#pragma warning( default : 4705 )

The warning pragma also supports the following syntax:

#pragma warning( push [ ,n ] )

#pragma warning( pop )

Where n represents a warning level (1 through 4).

The pragma warning( push ) stores the current warning state for all warnings. The pragma warning( push, n) stores the current state for all warnings and sets the global warning level to n.

The pragma warning( pop ) pops the last warning state pushed onto the stack. Any changes made to the warning state between push and pop are undone. Consider this example:

#pragma warning( push )
#pragma warning( disable : 4705 )
#pragma warning( disable : 4706 )
#pragma warning( disable : 4707 )
// Some code
#pragma warning( pop )

At the end of this code, pop restores the state of all warnings (including 4705, 4706, and 4707) to what it was at the beginning of the code.

When you write header files, you can use push and pop to ensure that changes to warning states made by the user do not prevent your headers from compiling properly. Use push at the beginning of the header and pop at the end. Suppose, for example, you have a header that does not compile cleanly at warning level 4. The following code changes the warning level to 3, then restores the original warning level at the end of the header:

#pragma warning( push, 3 )
// Declarations/ definitions
#pragma warning( pop )


Grammar Summary

This appendix describes the formal grammar of the preprocessor. It covers the syntax of preprocessing directives and operators discussed in Chapter 1, The Preprocessor, and Chapter 2, Pragma Directives.

The following topics are included:

  • Definitions

  • Conventions

  • Preprocessor Grammar


Definitions for the Grammar Summary

Terminals are endpoints in a syntax definition. No other resolution is possible. Terminals include the set of reserved words and user-defined identifiers.

Nonterminals are placeholders in the syntax. Most are defined elsewhere in this syntax summary. Definitions can be recursive. The following nonterminals are defined in the Grammar Summary of the C++ Language Reference:

constant, constant-expression, identifier, keyword, operator, punctuator

An optional component is indicated by the subscripted opt. For example, the following indicates an optional expression enclosed in curly braces:

{ expressionopt }


Conventions

The conventions use different font attributes for different components of the syntax. The symbols and fonts are as follows:

Attribute | Description
nonterminal | Italic type indicates nonterminals.
#include | Terminals in bold type are literal reserved words and symbols that must be entered as shown. Characters in this context are always case sensitive.
opt | Nonterminals followed by opt are always optional.
default typeface | Characters in the set described or listed in this typeface can be used as terminals in statements.

A colon (:) following a nonterminal introduces its definition. Alternative definitions are listed on separate lines.


Preprocessor Grammar

#define identifier token-stringopt

#define identifier[( identifieropt, ... , identifieropt )] token-stringopt

defined( identifier )

defined identifier

#include "path-spec"

#include <path-spec>

#line digit-sequence "filename"opt

#undef identifier

#error token-string

#pragma token-string

conditional :

if-part elif-partsopt else-partopt endif-line

if-part :

if-line text

if-line :

#if constant-expression
#ifdef identifier
#ifndef identifier

elif-parts :

elif-line text
elif-parts elif-line text

elif-line :

#elif constant-expression

else-part :

else-line text

else-line :

#else

endif-line :

#endif

digit-sequence :

digit
digit-sequence digit

digit : one of

0 1 2 3 4 5 6 7 8 9

token-string :

String of tokens

token :

keyword
identifier
constant
operator
punctuator

filename :

Legal operating system filename

path-spec :

Legal file path

text :

Any sequence of text

Note The following nonterminals are expanded in Appendix A, Grammar Summary, of the C++ Language Reference: constant, constant-expression, identifier, keyword, operator, and punctuator.


Language Quick Reference

This alphabetical reference describes C and C++ as implemented by Microsoft.
C/C++ Keywords
C/C++ Operators
Tables (data types, and so on)

Interesting home pages
Visual C++ Home The entire Visual C++ product.
Compiling and Linking Tools for building your program.
Preprocessor Reference Directives, pragmas, macros.


C/C++ Keywords

The following are keywords in Microsoft C and C++. Names with leading underscores are Microsoft extensions.

__asm | else | main | struct
__assume | enum | __multiple_inheritance | switch
auto | __except | __single_inheritance | template
__based | explicit | __virtual_inheritance | this
bool | extern | mutable | thread
break | false | naked | throw
case | __fastcall | namespace | true
catch | __finally | new | try
__cdecl | float | noreturn | __try
char | for | operator | typedef
class | friend | private | typeid
const | goto | protected | typename
const_cast | if | public | union
continue | inline | register | unsigned
__declspec | __inline | reinterpret_cast | using declaration, using directive
default | int | return | uuid
delete | __int8 | short | __uuidof
dllexport | __int16 | signed | virtual
dllimport | __int32 | sizeof | void
do | __int64 | static | volatile
double | __leave | static_cast | wmain
dynamic_cast | long | __stdcall | while


allocate

Microsoft Specific

__declspec(allocate(“segname”)) declarator

This declaration specifier specifies a data segment in which the data item will be allocated. The name segname must be declared using #pragma data_seg, #pragma code_seg, #pragma init_seg, or #pragma const_seg.

See Also __declspec

END Microsoft Specific


__asm

Microsoft Specific

__asm

assembly-language-instruction

__asm
{
assembly-language-instructions
}

If used without braces, the __asm keyword means that the rest of the line is an assembly-language statement. If used with braces, it means that each line between the braces is an assembly-language statement. For compatibility with previous versions, _asm is a synonym for __asm.

Since the __asm keyword is a statement separator, you can put assembly instructions on the same line.

For related information, see Assembler (Inline) Topics.

Note Microsoft C++ does not support the AT&T C++ asm keyword.

END Microsoft Specific

Example

// Example of the __asm keyword
__asm                  // __asm block
{
   mov eax, 01h
   int 10h
}

__asm mov eax, 01h      // Separate __asm lines
__asm int 10h

// Multiple __asm statements on a line
__asm mov eax, 01h   __asm int 10h


__assume

Microsoft Specific

__assume(expression)

The __assume keyword passes a hint to the optimizer. The optimizer assumes that the condition represented by expression is true at the point where the keyword appears and remains true until expression is altered (for example, by assignment to a variable). Selective use of hints passed to the optimizer by __assume can improve optimization.

The most common use of __assume is with the default case of a switch statement, as shown below.

Example

#ifdef DEGUG
# define ASSERT(e)    ( ((e) || assert(__FILE__, __LINE__) )
#else
# define ASSERT(e)    ( __assume(e) )
#endif

void gloo(int p)
{
   switch(p){
      case 1:
         blah(1);
         break;
      case 2:
         blah(-1);
         break;
      default:
         __assume(0);
            // This tells the optimizer that the default
            // cannot be reached. As so it does not have to generate
            // the extra code to check that 'p' has a value
            // not represented by a case arm.  This makes the switch
            // run faster.
   }
}

The use of __assume(0) tells the optimizer that the default case cannot be reached. As a result, the compiler does not generate code to test whether p has a value not represented in a case statement. Note that __assume(0) must be the first statement in the body of the default case for this to work.

Because the compiler generates code based on the __assume statement, that code may not correctly if the expression inside the __assume statement is false at runtime. If you are not sure that the expression will always be true at runtime, you can use the assert function to protect the code:

Example

# define ASSERT(e)    ( ((e) || assert(__FILE__, __LINE__)), __assume(e) )

Unfortunately, this use of assert prevents the compiler from performing the default-case optimization shown above. Therefore, you may want to use a separate macro instead:

Example

#ifdef DEBUG
# define NODEFAULT   ASSERT(0)
#else
# define NODEFAULT   __assume(0)
#endif

   default:
      NODEFAULT;

END Microsoft Specific


auto

auto declarator;

The auto keyword is the storage-class specifier indicating that the variable has local (automatic) extent. It is the default storage-class specifier for block-scoped variable declarations.

For related information, see extern, register, and static.


bad_cast Exception

C++ Specific

The dynamic_cast operator will throw a bad_cast exception as the result of a failed cast to a reference type. The interface for bad_cast is:

class bad_cast : public logic {
public:
   bad_cast(const __exString& what_arg) : logic(what_arg) {}
   void raise() { handle_raise(); throw *this; }
   // virtual __exString what() const;   //inherited
};

END C++ Specific


bad_typeid

C++ Specific

Under some circumstances, the typeid operator throws a bad_typeid exception. The interface for bad_typeid is:

class bad_typeid : public logic {
public:
   bad_typeid(const char * what_arg) : logic(what_arg) {}
   void raise()    { handle_raise(); throw *this; }
   // virtual __exString what() const;   //inherited
};

See typeid Operator for more information.

END C++ Specific


__based; _based

__based

Microsoft Specific

type __based( base ) declarator

The __based keyword specifies that a pointer is a 32-bit offset from a 32-bit pointer base. For compatibility with previous versions, _based is a synonym for __based.

END Microsoft Specific

Example

In the following example, the memory pointed to by bpi is adjusted by the base address value of vpi:

// Example of the __based keyword
int *vpi;
int __based(vpi)*bpi;

For more information, see #pragma alloc_text


bool

C++ Specific

bool declarators;

This keyword is an integral type. A variable of this type can have values true and false. All conditional expressions now return a value of type bool. For example, i!=0 now returns true or false depending on the value of i.

The values true and false have the following relationship:

!false == true
!true == false

In the following statement:

if (expres1) statement1;

If expres1 is true, statement1 is always executed; if expres1 is false, statement1 is never executed.

When a postfix or prefix ++ operator is applied to a variable of type bool, the variable is set to true. The postfix or prefix -- operator cannot be applied to a variable of this type.

The bool type participates in integral promotions. An r-value of type bool can be converted to an r-value of type int, with false becoming zero and true becoming one.

END C++ Specific

Microsoft Specific

In Visual C++4.2, the Standard C++ header files contained a typedef that equated bool with int. In Visual C++ 5.0 and later, bool is implemented as a built-in type with a size of 1 byte. That means that for Visual C++ 4.2, a call of sizeof(bool) yields 4, while in Visual C++ 5.0 and later, the same call yields 1. This can cause memory corruption problems if you have defined structure members of type bool in Visual C++ 4.2 and are mixing object files (OBJ) and/or DLLs built with the 4.2 and 5.0 or later compilers.

END Microsoft Specific


break Statement

break;

The break keyword terminates the smallest enclosing do, for, switch, or while statement in which it appears.

For more information, see switch, for, while, and continue.


_bstr_t

Microsoft and C++ Specific

One of the compiler COM support classes declared in COMDEF.H. It wraps the BSTR type to provide useful operators and methods. See the Compiler COM Support Classes for more information.

END Microsoft and C++ Specific


The __cdecl Keyword

See __cdecl.


class

C++ Specific

class [tag [: base-list ]]
{
member-list
} [declarators];
[ class ] tag declarators;

The class keyword declares a class type or defines an object of a class type.

The elements of a class definition are as follows:

tag

Names the class type. The tag becomes a reserved word within the scope of the class.

base-list

Specifies the class(es) from which the class is derived (its base classes). Each base class's name can be preceded by an access specifier (public, private, protected) and the virtual keyword. See the Table of Member Access Privileges for more information.

member-list

Declares members or friends of the class. Members can include data, functions, nested classes, enums, bit fields, and type names. Friends can include functions or classes. Explicit data initialization is not allowed. A class type cannot contain itself as a nonstatic member. It can contain a pointer or a reference to itself. See the virtual keyword and the Table of Member Access Privileges for more information.

declarators

Declares one or more objects of the class type.

END C++ Specific

Example

In the following example, the class CAboutDlg is derived from the base class CDialog. The new class contains one member function named CAboutDlg:

// Example of the class keyword
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
   CAboutDlg();

// Dialog Data
   //{{AFX_DATA(CAboutDlg)
   enum { IDD = IDD_ABOUTBOX };
   //}}AFX_DATA

// Implementation
protected:
   virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
   //{{AFX_MSG(CAboutDlg)
      // No message handlers
   //}}AFX_MSG
   DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
   //{{AFX_DATA_INIT(CAboutDlg)
   //}}AFX_DATA_INIT
}

For more information, see struct, union, __multiple_inheritance, __single_inheritance, and __virtual_inheritance.


_com_error

Microsoft and C++ Specific

One of the compiler COM support classes declared in COMDEF.H. It defines the error object thrown by _com_raise_error. See the Compiler COM Support Classes for more information.

END Microsoft and C++ Specific


_com_ptr_t

Microsoft and C++ Specific

One of the compiler COM support classes declared in COMDEF.H. It encapsulates COM interface pointers, and automates the required calls to AddRef, Release, and QueryInterface. See the Compiler COM Support Classes for more information.

END Microsoft and C++ Specific


const

const declaration

member-function const

When modifying a data declaration, the const keyword specifies that the object or variable is not modifiable. When following a member function's parameter list, the const keyword specifies that the function doesn't modify the object for which it is invoked. See Constant Values and Constant Member Functions for more information. Also see volatile and #define.


Constant Values

The const keyword specifies that a variable's value is constant and tells the compiler to prevent the programmer from modifying it.

const int i = 5;

i = 10; // Error
i++;    // Error

In C++, you can use the const keyword instead of the #define preprocessor directive to define constant values. Values defined with const are subject to type checking, and can be used in place of constant expressions. In C++, you can specify the size of an array with a const variable as follows:

const int maxarray = 255;
char store_char[maxarray];  // Legal in C++; illegal in C

In C, constant values default to external linkage, so they can appear only in source files. In C++, constant values default to internal linkage, which allows them to appear in header files.

The const keyword can also be used in pointer declarations.

char *const aptr = mybuf;  // Constant pointer

*aptr = 'a';       // Legal
aptr = yourbuf;    // Error

A pointer to a variable declared as const can be assigned only to a pointer that is also declared as const.

const char *bptr = mybuf;  // Pointer to constant data

*bptr = 'a';       // Error
bptr = yourbuf;    // Legal

You can use pointers to constant data as function parameters to prevent the function from modifying a parameter passed through a pointer.

You can call constant member functions only for a constant object. This ensures that the object is never modified.

birthday.getMonth();    // Okay
birthday.setMonth( 4 ); // Error

You can call either constant or nonconstant member functions for a nonconstant object. You can also overload a member function using the const keyword; this allows a different version of the function to be called for constant and nonconstant objects.

You cannot declare constructors or destructors with the const keyword.

See Also Constant Member Functions


Constant Member Functions

C++ Specific

Declaring a member function with the const keyword specifies that the function is a "read-only" function that does not modify the object for which it is called.

To declare a constant member function, place the const keyword after the closing parenthesis of the argument list. The const keyword is required in both the declaration and the definition. A constant member function cannot modify any data members or call any member functions that aren't constant.

END C++ Specific

Example

// Example of a constant member function
class Date
{
public:
   Date( int mn, int dy, int yr );
   int getMonth() const;       // A read-only function
   void setMonth( int mn );    // A write function;
                               //    cannot be const
private:
   int month;
};

int Date::getMonth() const
{
   return month;        // Doesn't modify anything
}
void Date::setMonth( int mn )
{
   month = mn;          // Modifies data member
}


const_cast Operator

C++ Specific

const_cast < type-id > ( expression )

The const_cast operator can be used to remove the const, volatile, and __unaligned attribute(s) from a class.

END C++ Specific


continue Statement

continue;

The continue keyword passes control to the next iteration of the smallest enclosing do, for, or while statement in which it appears.For more information, see for, while, and break.


__declspec

Microsoft Specific

__declspec ( extended-attribute ) declarator

extended-attribute
allocate(“segname”)
dllimport
dllexport
naked
noreturn
nothrow
novtable
property({get=get_func_name|, put=put_func_name})
selectany
thread
uuid(“ComObjectGUID”)

The extended attribute syntax for qualifying storage-class information simplifies and standardizes Microsoft-specific extensions to the C and C++ languages. Extended attribute syntax uses the __declspec keyword to qualify extended storage-class information. The __declspec keyword specifies that an instance of a given type is to be stored with a Microsoft-specific storage-class attribute.

Extended attribute syntax supports these Microsoft-specific storage-class attributes: allocate, thread, naked, dllimport, dllexport, nothrow, noreturn, novtable, and selectany. It also supports these COM-object attributes: property and uuid. These attributes are properties only of the declaration of the object or function to which they are applied; they do not redefine the type attributes of the object itself.

The __declspec keywords should be placed at the beginning of a simple declaration. THe compiler ignores, without warning, any __declspec keywords placed after * or & and in front of the variable identifier in a declaration.

A __declspec attribute specified in the beginning of a user-defined type declaration applies to the variable of that type. For example:

__declspec(dllimport) class X {} varX;

In this case, the attribute applies to varX. A __declspec attribute placed after the class or struct keyword applies to the user-defined type. For example:

class __declspec(dllimport) X {};

In this case, the attribute applies to X.

The general guideline for using the __declspec attribute for simple declarations is as follows:

decl-specifier-seq init-declarator-list;

The decl-specifier-seq should contain, among other things, a base type (e.g. int, float, a typedef, or a class name), a storage class (e.g. static, extern), or the __declspec extension. The init-declarator-list should contain, among other things, the pointer part of declarations. For example:

__declspec(selectany) int * pi1 = 0;   //OK, selectany & int both part of decl-specifier
int __declspec(selectany) * pi2 = 0;   //OK, selectany & int both part of decl-specifier
int * __declspec(selectany) pi3 = 0;   //ERROR, selectany is not part of a declarator

Example

The following code declares an integer thread local variable and initializes it with a value:

// Example of the __declspec keyword
__declspec( thread ) int tls_i = 1;

END Microsoft Specific


delete Operator

C++ Specific

[::] delete pointer

[::] delete [ ] pointer

The delete keyword deallocates a block of memory. The argument pointer must point to a block of memory previously allocated by the new operator. If pointer points to an array, place empty brackets before pointer.

Example

In the following example, the block of memory pointed to by pFile is deallocated:

// Example of the delete operator
CATCH_ALL(e)
   {
      ar.Close();
      delete pFile;
      THROW_LAST();
   }
   END_CATCH_ALL

END C++ Specific


dllimport, dllexport

Microsoft Specific

__declspec( dllimport ) declarator

__declspec( dllexport ) declarator

The dllexport and dllimport storage-class attributes are Microsoft-specific extensions to the C and C++ languages. They enable you to export and import functions, data, and objects to and from a DLL. These attributes explicitly define the DLL’s interface to its client, which can be the executable file or another DLL. Declaring functions as dllexport eliminates the need for a module-definition (.DEF) file, at least with respect to the specification of exported functions. Note that dllexport replaces the __export keyword.

The declaration of dllexport and dllimport uses extended attribute syntax.

For more information, see __declspec.

Example

// Example of the dllimport and dllexport class attributes
__declspec( dllimport ) int i;
__declspec( dllexport ) void func();

END Microsoft Specific


do Statement

do
statement
while( expression );

The do keyword executes statement repeatedly until expression becomes false (0).

Example

// Example of the do-while statement
do
{
    y = f( x );
    x--;
} while ( x > 0 );

In this do-while statement, the two statements y = f( x ); and x--; are executed, regardless of the initial value of x. Then x > 0 is evaluated. If x is greater than 0, the statement body is executed again and x > 0 is reevaluated. The statement body is executed repeatedly as long as x remains greater than 0. Execution of the do-while statement terminates when x becomes 0 or negative. The body of the loop is executed at least once.

For related information, see while, break, and continue.


dynamic_cast Operator

C++ Specific

dynamic_cast < type-id > ( expression )

The expression dynamic_cast< type-id >( expression ) converts the operand expression to an object of type type-id. The type-id must be a pointer or a reference to a previously defined class type or a "pointer to void". The type of expression must be a pointer if type-id is a pointer, or an l-value if type-id is a reference.

END C++ Specific


enum

enum [tag] {enum-list} [declarator]; // for definition of enumerated type

enum tag declarator; // for declaration of variable of type tag

The enum keyword specifies an enumerated type.

An enumerated type is a user-defined type consisting of a set of named constants called enumerators. By default, the first enumerator has a value of 0, and each successive enumerator is one larger than the value of the previous one, unless you explicitly specify a value for a particular enumerator. Enumerators needn’t have unique values. The name of each enumerator is treated as a constant and must be unique within the scope where the enum is defined. An enumerator can be promoted to an integer value. However, converting an integer to an enumerator requires an explicit cast, and the results are not defined.

In C, you can use the enum keyword and the tag to declare variables of the enumerated type. In C++, you can use the tag alone.

In C++, enumerators defined within a class are accessible only to member functions of that class unless qualified with the class name (for example, class_name::enumerator). You can use the same syntax for explicit access to the type name (class_name::tag).

For related information, see class and struct.

Example

// Example of the enum keyword
enum Days               // Declare enum type Days
{
   saturday,            // saturday = 0 by default
   sunday = 0,          // sunday = 0 as well
   monday,              // monday = 1
   tuesday,             // tuesday = 2
   wednesday,           // etc.
   thursday,
   friday
} today;                // Variable today has type Days

int  tuesday;           // Error, redefinition of tuesday

enum Days yesterday;    // Legal in C and C++
Days tomorrow;          // Legal in C++ only

yesterday = monday;

int i = tuesday;        // Legal; i = 2
yesterday = 0;          // Error; no conversion
yesterday = (Days)0;    // Legal, but results undefined


explicit

C++ Specific

This keyword is a declaration specifier that can only be applied to in-class constructor declarations. Constructors declared explicit will not be considered for implicit conversions. For example:

class X {
public:
   explicit X(int);      //legal
   explicit X(double) {   //legal
      // ...
   }
};

explicit X::X(int) {}      //illegal

An explicit constructor cannot take part in implicit conversions. It can only be used to explicitly construct an object. For example, with the class declared above:

void f(X) {}
void g(int I) {
   f(i);      // will cause error
}
void h() {
   X x1(1);      // legal
}

The function call f(i) fails because there is no available implicit conversion from int to X.

Note It is meaningless to apply explicit to constructors with multiple arguments, since such constructors cannot take part in implicit conversions.

END C++ Specific


extern

extern declarator // used when variable or function has external linkage

extern string-literal declarator // used when linkage conventions of another
                          // language are being used for the declarator

extern string-literal { declarator-list } // used when linkage conventions of another
                         // language are being used for the declarators

The extern keyword declares a variable or function and specifies that it has external linkage (its name is visible from files other than the one in which it's defined). When modifying a variable, extern specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends). The variable or function may be defined in another source file, or later in the same file. In C++, when used with a string, extern specifies that the linkage conventions of another language are being used for the declarator(s).

Declarations of variables and functions at file scope are external by default.

In C++, string-literal is the name of a language. The language specifier "C++" is the default. "C" is the only other language specifier currently supported by Microsoft C/C++. This allows you to use functions or variables defined in a C module.

All of the standard include files use the extern "C" syntax to allow the run-time library functions to be used in C++ programs.

For more information, see auto, register, static, const, and volatile.

Example

The following example declares the functions printf, getchar, and putchar with “C” linkage:

// Example of the extern keyword
extern "C" int printf( const char *, ... );

extern "C"
{
   int getchar( void );
   int putchar( int );
}


false

The keyword is one of the two values that a variable of type bool can have. For example, if i is a variable of type bool, the i=false; statement assigns false to i.


The __fastcall Keyword

See __fastcall.


for Statement

for( [init-expr]; [cond-expr]; [loop-expr] )
statement

The for keyword executes statement repeatedly.

First, the initialization (init-expr) is evaluated. Then, while the conditional expression (cond-expr) evaluates to a nonzero value, statement is executed and the loop expression (loop-expr) is evaluated. When cond-expr becomes 0, control passes to the statement following the for loop.

For more information, see while, break, and continue.

Example

// Example of the for statement
for ( i = space = tab = 0; i < MAX; i++ )
{
    if ( line[i] == ' ' )
        space++;
    if ( line[i] == '\t' )
    {
        tab++;
        line[i] = ' ';
    }
}

This example counts space (' ') and tab ('\t') characters in the array of characters named line and replaces each tab character with a space. First i, space, and tab are initialized to 0. Then i is compared with the constant MAX; if i is less than MAX, the statement body is executed. Depending on the value of line[i], the body of one or neither of the if statements is executed. Then i is incremented and tested against MAX; the statement body is executed repeatedly as long as i is less than MAX.


friend

C++ Specific —>

friend class-name;

friend function-declarator;

The friend keyword allows a function or class to gain access to the private and protected members of a class. See Friend Classes and Friend Functions for examples. Also see class, public, private, protected.

END C++ Specific


Friend Classes

C++ Specific —>

A friend class is a class all of whose member functions are friend functions of a class, that is, whose member functions have access to the other class's private and protected members.

Example

// Example of the friend class
class YourClass
{
friend class YourOtherClass;  // Declare a friend class
private:
   int topSecret;
};

class YourOtherClass
{
public:
   void change( YourClass yc );
};

void YourOtherClass::change( YourClass yc )
{
   yc.topSecret++;    // Can access private data
}

Friendship is not mutual unless explicitly specified as such. In the above example, member functions of YourClass cannot access the private members of YourOtherClass.

Friendship is not inherited, meaning that classes derived from YourOtherClass cannot access YourClass's private members; nor is it transitive, so classes that are friends of YourOtherClass cannot access YourClass's private members.

END C++ Specific


Friend Functions

C++ Specific —>

A friend function is a function that is not a member of a class but has access to the class's private and protected members.

A friend function is declared by the class that is granting access. The friend declaration can be placed anywhere in the class declaration. It is not affected by the access control keywords.

Example 1

A friend function is defined as a nonmember function:

class Complex
{
public:
   Complex( float re, float im );
   friend Complex operator+( Complex first, Complex second );
private:
   float real, imag;
};

Example 2

Complex operator+( Complex first, Complex second )
{
   return Complex( first.real + second.real,
                   first.imag + second.imag );
}

In this example, the friend function operator+ has access to the private data members of the Complex objects it receives as parameters.

Notice that the friend keyword does not appear in the function definition.

END C++ Specific


goto Statement

goto name;
. . .
name: statement

The goto keyword transfers control directly to the statement specified by the label name.

For related information, see if, return, and switch.

Example

In this example, a goto statement transfers control to the point labeled stop when i equals 5.

// Example of the goto statement
void main()
{
    int i, j;

    for ( i = 0; i < 10; i++ )
    {
        printf( "Outer loop executing. i = %d\n", i );
        for ( j = 0; j < 3; j++ )
        {
            printf( " Inner loop executing. j = %d\n", j );
            if ( i == 5 )
                goto stop;
        }
    }
    /* This message does not print: */
    printf( "Loop exited. i = %d\n", i );
    stop: printf( "Jumped to stop. i = %d\n", i );
}


if, else Statements

if( expression )
statement1
[else
statement2]

The if keyword executes statement1 if expression is true (nonzero); if else is present and expression is false (zero), it executes statement2. After executing statement1 or statement2, control passes to the next statement.

For related information, see switch.

Example 1

if ( i > 0 )
    y = x / i;
else
{
    x = i;
    y = f( x );
}

In this example, the statement y = x/i; is executed if i is greater than 0. If i is less than or equal to 0, i is assigned to x and f( x ) is assigned to y. Note that the statement forming the if clause ends with a semicolon.

When nesting if statements and else clauses, use braces to group the statements and clauses into compound statements that clarify your intent. If no braces are present, the compiler resolves ambiguities by associating each else with the closest if that lacks an else.

Example 2

if ( i > 0 )           /* Without braces */
    if ( j > i )
        x = j;
    else
        x = i;

The else clause is associated with the inner if statement in this example. If i is less than or equal to 0, no value is assigned to x.

Example 3

if ( i > 0 )
{                      /* With braces */
    if ( j > i )
        x = j;
}
else
    x = i;

The braces surrounding the inner if statement in this example make the else clause part of the outer if statement. If i is less than or equal to 0, i is assigned to x.


Inheritance Keywords

C++ Specific —>

class [__single_inheritance] class-name;

class [__multiple_inheritance] class-name;

class [__virtual_inheritance] class-name;

class-name

The name of the class being declared.

If you need to declare a pointer to a member of a class prior to defining the class, you can specify the inheritance used in the class declaration using the __single_inheritance, __multiple_inheritance, or __virtual_inheritance keywords described here, thus allowing control of the code generated on a per-class basis. Or you can use either the /vmg compiler option or the related pointers_to_members pragma.

Note If you always declare a pointer to a member of a class after defining the class, you don't need to use any of these options.

Declaring a pointer to a member of a class prior to the class definition affects the size and speed of the resulting executable file. The number of bytes required to represent a pointer to a member of a class and the code required to interpret the representation may depend on whether the class is defined with no, single, multiple, or virtual inheritance.

In general, the more complex the inheritance used by a class, the greater the number of bytes required to represent a pointer to a member of the class and the larger the code required to interpret the pointer.

As shown in this example,

class __single_inheritance S;
int S::*p;

regardless of command-line options or pragmas, pointers to members of class S will use the smallest possible representation.

Note The same forward declaration of a class pointer-to-member representation should occur in every translation unit that declares pointers to members of that class, and the declaration should occur before the pointers to members are declared.

END C++ Specific


inline, __inline, __forceinline

inline

function_declarator; // C++ Specific

__inline

function_declarator;// Microsoft Specific

__forceinline

function_declarator;// Microsoft Specific

The inline and __inline keywords allow the compiler to insert a copy of the function body into each place the function is called. The insertion occurs only if the compiler's cost/benefit analysis show it to be profitable. The __forceinline keyword overrides the cost/benefit analysis and relies on the judgement of the programmer instead. Exercise caution when using __forceinline. Indiscriminate use of __forceinline can result in larger code with only marginal performance gains or, in some cases, even performance losses (due to increased paging of a larger executable, for example).

You cannot force the compiler to inline a function when conditions other than cost/benefit analysis prevent it. You cannot inline a function if:

  • The function or its caller is compiled with /Ob0 (the default option for debug builds).

  • The function and the caller use different types of exception handling (C++ exception handling in one, structured exception handling in the other).

  • The function has a variable argument list.

  • The function uses inline assembly and is not compiled with /Og, /Ox, /O1, or /O2).

  • Function returns an unwindable object by value and is not compiled with /GX, /EHs, or /EHa).

  • The function receives a copy-constructed object passed by value, when compiled with /GX, /EHs,, or /EHa.

  • The function is recursive and is not accompanied by #pragma(inline_recursion, on). With the pragma, recursive functions can be inlined to a default depth of eight calls. To change the inlining depth, use #pragma(inline_depth, n) .

If the compiler cannot inline a function declared __forceinline, it generates a level 1 warning (4714).

The inline keyword is available only in C++. The __inline and __forceinline keywords are available in both C and C++. For compatibility with previous versions, _inline is a synonym for __inline.

Using inline functions can make your program faster because they eliminate the overhead associated with function calls. Functions expanded inline are subject to code optimizations not available to normal functions.

The /Ob compiler optimization option determines whether inline function expansion actually occurs.

For related information, see auto_inline.

Example 1

inline int max( int a , int b )
{
   if( a > b ) return a;
   return b;
}

A class's member functions can be declared inline either by using the inline keyword or by placing the function definition within the class definition.

Example 2

class MyClass
{
public:
   void print() { cout << i << ''; }  // Implicitly inline
private:
   int i;
};

See Also Assembler (Inline) Topics


__int8, __int16, __int32, __int64

Microsoft Specific —>

Microsoft C/C++ features support for sized integer types. You can declare 8-, 16-, 32-, or 64-bit integer variables by using the __int n type specifier, where n is 8, 16, 32, or 64.

The following example declares one variable for each of these types of sized integers:

__int8 nSmall;      // Declares 8-bit integer
__int16 nMedium;    // Declares 16-bit integer
__int32 nLarge;     // Declares 32-bit integer
__int64 nHuge;      // Declares 64-bit integer

The types __int8, __int16, and __int32 are synonyms for the ANSI types that have the same size, and are useful for writing portable code that behaves identically across multiple platforms. Note that the __int8 data type is synonymous with type char, __int16 is synonymous with type short, and __int32 is synonymous with type int. The __int64 type has no ANSI equivalent.

C++ Specific —>

Because __int8, __int16, and __int32 are considered synonyms by the compiler, care should be taken when using these types as arguments to overloaded function calls. The following C++ code generates a compiler error:

void MyFunc( __int8 ) {}
void MyFunc( char ) {}

void main()
{
    __int8 newVal;
    char MyChar;
    MyFunc( MyChar );    // Ambiguous function calls;
    MyFunc( newVal );    // char is synonymous with __int8.
}

END C++ Specific

END Microsoft Specific


main, wmain

main( int argc, char *argv[ ], char *envp[ ] )
{
program-statements
}

wmain( int argc, wchar_t *argv[ ], wchar_t *envp[ ] )
{
program-statements
}

The main function marks the beginning and end of program execution. A C or C++ program must have one function named main. If your code adheres to the Unicode programming model, you can use the wide-character version of main, which is wmain.

The main and wmain functions can take the following three optional arguments, traditionally called argc, argv, and envp (in that order):

argc

An integer specifying how many arguments are passed to the program from the command line. Because the program name is considered an argument, argc is at least 1.

argv

An array of null-terminated strings. It can be declared as an array of pointers to char (char *argv[ ] or wchar_t *argv[ ] for wmain) or as a pointer to pointers to char (char **argv or wchar_t **argv for wmain). The first string (argv[0]) is the program name, and each following string is an argument passed to the program from the command line. The last pointer (argv[argc]) is NULL.

Microsoft Specific —>

envp

A pointer to an array of environment strings. It can be declared as an array of pointers to char (char *envp[ ]) or as a pointer to pointers to char (char **envp). If your program uses wmain instead of main, use the wchar_t data type instead of char. The end of the array is indicated by a NULL pointer. The environment block passed to main and wmain is a “frozen” copy of the current environment. If you subsequently change the environment via a call to putenv or _wputenv, the current environment (as returned by getenv/_wgetenv and the _environ/ _wenviron variable) will change, but the block pointed to by envp will not change. This argument is ANSI compatible in C, but not in C++.

END Microsoft Specific


mutable

C++ Specific —>

mutable member-variable-declaration;

This keyword can only be applied to non-static and non-const data members of a class. If a data member is declared mutable, then it is legal to assign a value to this data member from a const member function.

END C++ Specific


naked

Microsoft Specific —>

__declspec( naked ) declarator

For functions declared with the naked attribute, the compiler generates code without prolog and epilog code. You can use this feature to write your own prolog/epilog code using inline assembler code. Naked functions are particularly useful in writing virtual device drivers.

Because the naked attribute is relevant only to the definition of a function and is not a type modifier, naked functions use the C++ Extended Storage-Class Attributes syntax.

For related information, see __declspec The naked Attribute Argument Passing and Naming Conventions Naked Function Calls.

Example

This code defines a function with the naked attribute:

// Example of the naked attribute
__declspec( naked ) int func( formal_parameters )
{
    // Function body
}

END Microsoft Specific


namespace Declaration

C++ Specific —>

namespace [identifier] { namespace-body }

A namespace declaration identifies and assigns a name to a declarative region.

The identifier in a namespace declaration must be unique in the declarative region in which it is used. The identifier is the name of the namespace and is used to reference its members.

The declarative region of a namespace declaration is its namespace-body.

END C++ Specific


new Operator

C++ Specific —>

[::] new [placement] type-name [initializer]

[::] new [placement] ( type-name ) [initializer]

The new keyword allocates memory for an object of type-name from the free store and returns a suitably typed, nonzero pointer to an object. If unsuccessful, by default new returns zero. You can change this default behavior by writing a custom exception-handling routine and calling the _set_new_handler run-time library function with your function name as its argument.

Use the delete operator to deallocate the memory allocated with the new operator.

The following list describes the elements of new:

placement

Provides a way of passing additional arguments if you overload new.

type-name

Specifies type to be allocated. If the type specification is complicated, it can be surrounded by parentheses to force the order of binding.

initializer

Provides a value for the initialized object. Initializers cannot be specified for arrays. The new operator will create arrays of objects only if the class has a default constructor.

END C++ Specific

Examples

The following statement allocates an integer.

int *pi = new int;

The following statement allocates a character and initializes it.

char *pc = new char( 'a' );

The following statement allocates an instance of Date using the class's three-argument constructor, and returns a pointer to it.

Date *pmc = new Date( 3, 12, 1985 );

The following statement allocates an array of characters.

char *pstr = new char[sizeof( str )];

The following statement allocates a two-dimensional array of characters of size dim * 10. When allocating a multidimensional array, all dimensions except the first must be constant expressions.

char (*pchar)[10] = new char[dim][10];

The following statement allocates an array of seven pointers to functions that return integers.

int (**p) () = new (int (*[7]) ());

If you use the operator new without any extra arguments, and compile with the /GX, /EHs, or /EHa option, the compiler will generate code to call operator delete if the constructor throws an exception.

If you use the placement new form of the new operator, the form with arguments in addition to the size of the allocation, the compiler does not support a placement form of the delete operator if the constructor throws an exception.

Example

class A {
public:
    A(int) { throw "Fail!"; }
};
void foo(void)
{
    try {
        // heap memory pointed to by pa1 will be deallocated
        // by calling ::operator delete(void*).
        A* pa1 = new A(10);
    } catch (...) {
    }
    try {
        // This will call ::operator new(size_t, char*, int).
        // When A::A(int) does a throw, we should call
        // ::operator delete(void*, char*, int) to deallocate
        // the memory pointed to by pa2, but that's something
        // we don't support yet, so we'll leak memory.
        A* pa2 = new(__FILE__, __LINE__) A(20);
    } catch (...) {
    }
}


noreturn

Microsoft and C++ Specific —>

This __declspec attribute tells the compiler that a function does not return. As a consequence, the compiler knows that the code following a call to a __declspec(noreturn) function is unreachable.

If the compiler finds a function with a control path that does not return a value, it generates a warning (C4715) or error message (C2202). If the control path cannot be reached due to a function that never returns, you can use __declspec(noreturn) to prevent this warning or error.

Consider, for example, the following code. The else clause does not contain a return statement, so the programmer declares fatal as __declspec(noreturn) to avoid an error or warning message.

__declspec(noreturn) extern void fatal ()
{
   // Code omitted
}

int gloo()
{
   if(...)
     return 1;
   else if(...)
     return 0;
   else
     fatal();
}

END Microsoft and C++ Specific


nothrow

Microsoft and C++ Specific —>

This is a __declspec extended attribute which can be used in the declaration of functions. This attribute tells the compiler that the declared function and the functions it calls never throw an exception. With the synchronous exception handling model, now the default, the compiler can eliminate the mechanics of tracking the lifetime of certain unwindable objects in such a function, and significantly reduce the code size.

The following three declarations are equivalent:

#define WINAPI __declspec(nothrow) __stdcall

void WINAPI foo1();
void __declspec(nothrow) __stdcall foo2();
void __stdcall foo3() throw();

Using void __declspec(nothrow) __stdcall foo2(); has the advantage that you can use an API definition, such as the illustrated by the #define statement, to easily specify nothrow on a set of functions. The third declaration, void __stdcall foo3() throw(); is the syntax defined by the C++ standard.

See Synchronous Exception Handling for more information.

END Microsoft and C++ Specific


novtable

Microsoft and C++ Specific —>

This is a __declspec extended attribute.

This form of _declspec can be applied to any class declaration, but should only be applied to pure interface classes, that is classes that will never be instantiated on their own. The _declspec stops the compiler from generating code to initialize the vfptr in the constructor(s) and destructor of the class. In many cases, this removes the only references to the vtable that are associated with the class and, thus, the linker will remove it. Using this form of _declspec can result in a significant reduction in code size.

END Microsoft and C++ Specific


operator

C++ Specific —>

type operator operator-symbol ( parameter-list )

The operator keyword declares a function specifying what operator-symbol means when applied to instances of a class. This gives the operator more than one meaning, or "overloads" it. The compiler distinguishes between the different meanings of an operator by examining the types of its operands.

Rules of Operator Overloading

  • You can overload the following operators:
    + - * / % ^
    ! = < > += –=
    ^= &= |= << >> <<=
    <= >= && || ++ ––
    ( ) [ ] new delete & |
    ~ *= /= %= >>= ==
    != , –> –>*

  • If an operator can be used as either a unary or a binary operator, you can overload each use separately.

  • You can overload an operator using either a nonstatic member function or a global function that's a friend of a class. A global function must have at least one parameter that is of class type or a reference to class type.

  • If a unary operator is overloaded using a member function, it takes no arguments. If it is overloaded using a global function, it takes one argument.

  • If a binary operator is overloaded using a member function, it takes one argument. If it is overloaded using a global function, it takes two arguments.

Restrictions on Operator Overloading

  • You cannot define new operators, such as **.

  • You cannot change the precedence or grouping of an operator, nor can you change the numbers of operands it accepts.

  • You cannot redefine the meaning of an operator when applied to built-in data types.

  • Overloaded operators cannot take default arguments.

  • You cannot overload any preprocessor symbol, nor can you overload the following operators:
    . .* :: ?:

  • The assignment operator has some additional restrictions. It can be overloaded only as a nonstatic member function, not as a friend function. It is the only operator that cannot be inherited; a derived class cannot use a base class's assignment operator.

For more information, see C/C++ Operators and Operator Precedence Table.

END C++ Specific

Example

The following example overloads the + operator to add two complex numbers and returns the result.

// Example of the operator keyword
class Complex
{
public:
   Complex( float re, float im );
   Complex operator+( Complex &other );
   friend Complex operator+( int first, Complex &second );
private:
   float real, imag;
};

// Operator overloaded using a member function
Complex Complex::operator+( Complex &other )
{
return Complex( real + other.real, imag + other.imag );
};

// Operator overloaded using a friend function
Complex operator+( int first, Complex &second )
{
return Complex( first + second.real, second.imag );
}


private

C++ Specific —>

private: [member-list]

private base-class

When preceding a list of class members, the private keyword specifies that those members are accessible only from member functions and friends of the class. This applies to all members declared up to the next access specifier or the end of the class.

When preceding the name of a base class, the private keyword specifies that the public and protected members of the base class are private members of the derived class.

Default access of members in a class is private. Default access of members in a structure or union is public.

Default access of a base class is private for classes and public for structures. Unions cannot have base classes.

For related information, see friend, public, protected, and Table of Member Access Privileges.

END C++ Specific

Example

// Example of the private keyword
class BaseClass
{ public:
   // privMem accessible from member function
   int pubFunc() { return privMem; }
private:
   void privMem;
};

class DerivedClass : public BaseClass
{
public:
   void usePrivate( int i )
      { privMem = i; }   // Error: privMem not accessible
                        //    from derived class
};

class DerivedClass2 : private BaseClass
{
public:
   // pubFunc() accessible from derived class
   int usePublic() { return pubFunc(); }
};

void main()
{
   BaseClass aBase;
   DerivedClass aDerived;
   DerivedClass2 aDerived2;
   aBase.privMem = 1;     // Error: privMem not accessible
   aDerived.privMem = 1;  // Error: privMem not accessible
                          //    in derived class
   aDerived2.pubFunc();   // Error: pubFunc() is private in
                          //    derived class
}


Table of Member Access Privileges

C++ Specific —>

Access in Base Class | Base Class Inherited as | Access in Derived Class
Public Protected Private | Public | Public Protected No access1
Public Protected Private | Protected | Protected Protected No access1
Public Protected Private | Private | Private Private No access1

1 Unless friend declarations within the base class explicitly grant access.

END C++ Specific


property

Microsoft Specific —>

__declspec( property( get=get_func_name ) ) declarator

__declspec( property( put=put_func_name ) ) declarator

__declspec( property( get=get_func_name, put=put_func_name ) ) declarator

This attribute can be applied to non-static “virtual data members” in a class or structure definition. The compiler treats these “virtual data members” as data members by changing their references into function calls.

When the compiler sees a data member declared with this attribute on the right of a member-selection operator (“.” or “->“), it converts the operation to a get or put function, depending on whether such an expression is an l-value or an r-value. In more complicated contexts, such as “+=“, a rewrite is performed by doing both get and put.

This attribute can also be used in the declaration of an empty array in a class or structure definition. For example:

__declspec(property(get=GetX, put=PutX)) int x[];

The above statement indicates that x[] can be used with one or more array indices. In this case, i=p->x[a][b] will be turned into i=p->GetX(a, b), and p->x[a][b] = i will be turned into p->PutX(a, b, i);

END Microsoft Specific

See Also __declspec


protected

C++ Specific —>

protected: [member-list]

protected base-class

When preceding a list of class members, the protected keyword specifies that those members are accessible only from member functions and friends of the class and its derived classes. This applies to all members declared up to the next access specifier or the end of the class.

When preceding the name of a base class, the protected keyword specifies that the public and protected members of the base class are protected members of the derived class.

Default access of members in a class is private. Default access of members in a structure or union is public.

Default access of a base class is private for classes and public for structures. Unions cannot have base classes.

For related information, see public, private, friend, and Table of Member Access Privileges.

END C++ Specific

Example

// Example of the protected keyword
class BaseClass
{
protected:
   int protectFunc();
};

class DerivedClass : public BaseClass
{
public:
   int useProtect()
      { protectFunc(); }    // protectFunc accessible
                           //    from derived class
};

void main()
{
BaseClass aBase;
DerivedClass aDerived;
   aBase.protectFunc();     // Error: protectFunc not
                            //    accessible
   aDerived.protectFunc();  // Error: protectFunc not
                            //    accessible in derived class
}


public

C++ Specific —>

public: [member-list]

public base-class

When preceding a list of class members, the public keyword specifies that those members are accessible from any function. This applies to all members declared up to the next access specifier or the end of the class.

When preceding the name of a base class, the public keyword specifies that the public and protected members of the base class are public and protected members, respectively, of the derived class.

Default access of members in a class is private. Default access of members in a structure or union is public.

Default access of a base class is private for classes and public for structures. Unions cannot have base classes.

For more information, see private, protected, friend, and Table of Member Access Privileges.

END C++ Specific

Example

// Example of the public keyword
class BaseClass
{
public:
   int pubFunc();
};

class DerivedClass : public BaseClass
{
};
void main()
{
   BaseClass aBase;
   DerivedClass aDerived;
   aBase.pubFunc();       // pubFunc() is accessible
                          //    from any function
   aDerived.pubFunc();    // pubFunc() is still public in
                          //    derived class
}


register

register declarator

The register keyword specifies that the variable is to be stored in a machine register, if possible.

The 32-bit compiler does not honor user requests for register variables. Instead it makes its own register choices when global optimizations are on. However, all other semantics associated with the register keyword are honored by the 32-bit compiler.

For more information, see auto, extern, and static.


reinterpret_cast Operator

C++ Specific —>

reinterpret_cast < type-id > ( expression )

The reinterpret_cast operator allows any pointer to be converted into any other pointer type, and it allows any integral type to be converted into any pointer type and vice versa. Misuse of the reinterpret_cast operator can easily be unsafe. Unless the desired conversion is inherently low-level, you should use one of the other cast operators.

END C++ Specific


return Statement

return [expression];

The return keyword terminates execution of the function in which it appears and returns control (and the value of expression if given) to the calling function. A function returns an integer value by default. To define other types of return values, the name of the function is preceded by the type. If the function is type void, the return statement is omitted.

Example

In the following example, a simple function with no parameters returns integer 0:

// Examples of the return statement
cypher()
   {
   return(0);
   }

In the following example, a simple function with no parameters returns a double value:

double fMultip()
   {
   double a;
   a = 4 * 3;
   return (a);
   }


selectany

Microsoft Specific —>

__declspec( selectany ) declarator

This attribute tells the compiler that the declared global data item is a pick-any COMDAT. At link time, if multiple definitions of a COMDAT are seen, the linker picks one and discards the rest. If the linker option /OPT:REF (Optimizations) is selected, then COMDAT elimination will occur to remove all the unreferenced data items in the linker output.

A global data item can normally be initialized only once in an EXE or DLL project. This attribute can be used in initializing global data defined by headers, when the same header appears in more than one source file. This attribute is available in both the C and C++ compilers.

Note This attribute can only be applied to the actual initialization of global data items that are externally visible.

END Microsoft Specific

Example

This code shows how to use the selectany attribute:

//Correct - x1 is initialized and externally visible
__declspec(selectany) int x1=1;

//Incorrect - const is by default static in C++, so
//x2 is not visible externally (This is OK in C, since
//const is not by default static in C)
const __declspec(selectany) int x2 =2;

//Correct - x3 is extern const, so externally visible
extern const __declspec(selectany) int x3=3;

//Correct - x4 is extern const, so it is externally visible
extern const int x4;
const __declspec(selectany) int x4=4;

//Incorrect - __declspec(selectany) is applied to the uninitialized
//declaration of x5
extern __declspec(selectany) int x5;

See Also __declspec


sizeof Operator

sizeof expression

The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.

The expression is either an identifier or a type-cast expression (a type specifier enclosed in parentheses).

When applied to a structure type or variable, sizeof returns the actual size, which may include padding bytes inserted for alignment. When applied to a statically dimensioned array, sizeof returns the size of the entire array. The sizeof operator cannot return the size of dynamically allocated arrays or external arrays.

For related information, see Operators.

Example

// Example of the sizeof keyword
size_t  i = sizeof( int );

struct align_depends {
    char c;
    int i;
};
size_t size = sizeof(align_depends);  // The value of size depends on
                                   //  the value set with /Zp or
                                   //  #pragma pack

int  array[] = { 1, 2, 3, 4, 5 };     // sizeof( array ) is 20
                                      // sizeof( array[0] ) is 4
size_t  sizearr =                        // Count of items in array
   sizeof( array ) / sizeof( array[0] );


static

static declarator

When modifying a variable, the static keyword specifies that the variable has static duration (it is allocated when the program begins and deallocated when the program ends) and initializes it to 0 unless another value is specified. When modifying a variable or function at file scope, the static keyword specifies that the variable or function has internal linkage (its name is not visible from outside the file in which it is declared).

In C++, when modifying a data member in a class declaration, the static keyword specifies that one copy of the member is shared by all the instances of the class. When modifying a member function in a class declaration, the static keyword specifies that the function accesses only static members.

For related information, see auto, extern, and register.

Example

// Example of the static keyword
static int i;         // Variable accessible only from this file

static void func();   // Function accessible only from this file

int max_so_far( int curr )
{
   static int biggest;    // Variable whose value is retained
                          //    between each function call
   if( curr > biggest )
      biggest = curr;

   return biggest;
}

// C++ only

class SavingsAccount
{
public:
   static void setInterest( float newValue )  // Member function
      { currentRate = newValue; }             //    that accesses
                                              //    only static
                                              //    members
private:
   char name[30];
   float total;
   static float currentRate;    // One copy of this member is
                                //    shared among all instances
                                //    of SavingsAccount
};

// Static data members must be initialized at file scope, even
//    if private.
float SavingsAccount::currentRate = 0.00154;


static_cast Operator

C++ Specific —>

static_cast < type-id > ( expression )

The expression static_cast < type-id > ( expression ) converts expression to the type of type-id based solely on the types present in the expression. No run-time type check is made to ensure the safety of the conversion.

END C++ Specific


The __stdcall Keyword

See __stdcall.


struct

struct [tag] { member-list } [declarators];

[struct] tag declarators;

The struct keyword defines a structure type and/or a variable of a structure type. See Anonymous Structures and Unsized Array in a Structure for more information.

A structure type is a user-defined composite type. It is composed of "fields" or "members" that can have different types.

In C++, a structure is the same as a class except that its members are public by default.

Using a Structure

In C, you must explicitly use the struct keyword to declare a structure. In C++, this is unnecessary once the type has been defined.

You have the option of declaring variables when the structure type is defined by placing one or more comma-separated variable names between the closing brace and the semicolon.

For related information, see class, union, and enum.

Example 1

struct PERSON              // Declare PERSON struct type
{
   int   age;              // Declare member types
   long  ss;
   float weight;
   char  name[25];
} family_member;           // Define object of type PERSON

   struct PERSON sister;   // C style structure declaration
   PERSON brother;         // C++ style structure declaration

   sister.age  = 13;       // assign values to members
   brother.age =  7;

Structure variables can be initialized. The initialization for each variable must be enclosed in braces.

Example 2

struct POINT            // Declare POINT structure
{
   int x;               // Define members x and y
   int y;
} spot = { 20, 40 };    // Variable spot has
                        //     values x = 20, y = 40
struct POINT there;     // Variable there has POINT type
struct CELL             // Declare CELL bit field
{
   unsigned character  : 8;  // 00000000 ????????
   unsigned foreground : 3;  // 00000??? 00000000
   unsigned intensity  : 1;  // 0000?000 00000000
   unsigned background : 3;  // 0???0000 00000000
   unsigned blink      : 1;  // ?0000000 00000000
} screen[25][80];       // Array of bit fields


Anonymous Structures

Microsoft Specific —>

A Microsoft C extension allows you to declare a structure variable within another structure without giving it a name. These nested structures are called anonymous structures. C++ does not allow anonymous structures.

You can access the members of an anonymous structure as if they were members in the containing structure.

END Microsoft Specific

Example

// Example of an anonymous structure
struct phone
{
   int  areacode;
   long number;
};

struct person
{
   char   name[30];
   char   sex;
   int    age;
   int    weight;
   struct phone;    // Anonymous structure; no name needed
} Jim;

Jim.number = 1234567;


Unsized Arrays in Structures

Microsoft Specific —>

A Microsoft extension allows the last member of a C or C++ structure or class to be a variable-sized array. These are called unsized arrays. The unsized array at the end of the structure allows you to append a variable-sized string or other array, thus avoiding the run-time execution cost of a pointer dereference.

struct PERSON
{
   unsigned number;
   char     name[];    // Unsized array
};

If you apply the sizeof operator to this structure, the ending array size is considered to be 0. The size of this array is 2 bytes, which is the size of the unsigned member. To get the true size of a variable of type PERSON, you would need to obtain the array size separately.

The size of the structure is added to the size of the array to get the total size to be allocated. After allocation, the array is copied to the array member of the structure, as shown below:

struct PERSON *ptr;
char who[40];

printf( "Enter name: " );
gets( who );

// Allocate space for structure, name, and terminating null
ptr = malloc( sizeof( struct PERSON ) + strlen( who ) + 1 );

// Copy the string to the name member
strcpy( ptr->name, who );

Even after the structure variable's array is initialized, the sizeof operator returns the size of the variable without the array.

Structures with unsized arrays can be initialized, but arrays of such structures cannot be initialized.

struct PERSON me  = { 6, "Me" };        // Legal
struct PERSON you = { 7, "You" };

struct PERSON us[2] = { { 8, "Them" },  // Error
                        { 9, "We" } };

An array of characters initialized with a string literal gets space for the terminating null; an array initialized with individual characters (for example, {'a', 'b', 'c'}) does not.

A structure with an unsized array can appear in other structures, as long as it is the last member declared in its enclosing structure. Classes or structures with unsized arrays cannot have direct or indirect virtual bases.

For related information, see volatile and #define.

END Microsoft Specific


switch, case, default Statements

switch( expression )
{
[case constant-expression:]
. . .
[statement]
. . .
[default:
statement]
}

The switch and case keywords evaluate expression and execute any statement associated with constant-expression whose value matches the initial expression.

If there is no match with a constant expression, the statement associated with the default keyword is executed. If the default keyword is not used, control passes to the statement following the switch block.

For related information, see if and break.

Examples

All three statements of the switch body in the following example are executed if c is equal to 'A' since a break statement does not appear before the following case. Execution control is transferred to the first statement (capa++;) and continues in order through the rest of the body. If c is equal to 'a', lettera and total are incremented. Only total is incremented if c is not equal to 'A' or 'a'.

switch( c )
{
    case 'A':
        capa++;
    case 'a':
        lettera++;
    default :
        total++;
}

In the following example, a break statement follows each statement of the switch body. The break statement forces an exit from the statement body after one statement is executed. If i is equal to –1, only n is incremented. The break following the statement n++; causes execution control to pass out of the statement body, bypassing the remaining statements. Similarly, if i is equal to 0, only z is incremented; if i is equal to 1, only p is incremented. The final break statement is not strictly necessary, since control passes out of the body at the end of the compound statement, but it is included for consistency.

switch( i )
{
    case -1:
        n++;
        break;
    case 0 :
        z++;
        break;
    case 1 :
        p++;
        break;
}


template

C++ Specific —>

template < [typelist] [, [ arglist ]] > declaration

The template declaration specifies a set of parameterized classes or functions.

The template parameter list is a comma-separated list of types (in the form class identifier or typename identifier) or a non-type to be used in the template body. The declaration field must be a declaration of a function or class.

You can instantiate a class template much like you would instantiate a normal class, but include the template arguments within angle brackets. No special syntax is required to call a function template.

See Also Template Topics

END C++ Specific

Example

// Example of the template keyword
template <class T, int i> class TestClass {
public:
   char buffer[i];
   T testFunc(T* p1 );
};

template <class T, int i>
T TestClass<T,i>::testFunc(T* p1) {
    return *(p1++)
};

// To create an instance of TestClass
TestClass<char, 5> ClassInst;


this

C++ Specific —>

The this pointer is a pointer accessible only within the member functions of a class, struct, or union type. It points to the object for which the member function is called. Static member functions do not have a this pointer.

When a nonstatic member function is called for an object, the address of the object is passed as a hidden argument to the function. For example, the following function call

myDate.setMonth( 3 );

can be interpreted this way:

setMonth( &myDate, 3 );

The object's address is available from within the member function as the this pointer. It is legal, though unnecessary, to use the this pointer when referring to members of the class.

The expression (*this) is commonly used to return the current object from a member function.

Note Modifying the this pointer is illegal in the latest version of C++.

END C++ Specific

Example

// Example of the this pointer
void Date::setMonth( int mn )
{
   month = mn;            // These three statements
   this->month = mn;      //     are equivalent
   (*this).month = mn;
}


thread

Microsoft Specific —>

__declspec( thread ) declarator

Thread Local Storage (TLS) is the method by which each thread in a given multithreaded process allocates storage for thread-specific data.

The thread extended storage-class modifier is used to declare a thread local variable. The thread attribute must be used with the __declspec keyword.

The use of __declspec(thread) may interfere with delay loading of DLL imports.

For related information, see __declspec.

Example

The following code declares an integer thread local variable and initializes it with a value:

// Example of the thread attribute
__declspec( thread ) int tls_i = 1;

See Also Thread Local Storage (TLS)

END Microsoft Specific


true

This keyword is one of the two values that a variable of type bool can have. If i is of type bool, then the statement i=true; assigns true to i.


Exception Handling Mechanisms

Microsoft C/C++ provides two different forms of support for handling anomalous situations, known as “exceptions,” which may occur during the execution of your program. These two forms are C++ exception handling and structured exception handling .

C++ Exception Handling

C++ exception handling uses three statements added to the C++ language. These are the try, catch, and throw statements. With C++ exception handling, your program can communicate unexpected events to a higher execution context that is better able to recover from such abnormal events. These exceptions are handled by code that is outside the normal flow of control. The Microsoft C++ compiler implements the C++ exception handling model based on the ISO WG21/ANSI X3J16 working papers towards the evolving standard for C++.

Structured Exception Handling

Structured exception handling is an extension to Microsoft C/C++ that can be used in either C or C++. Structured exception handling uses two constructs: try-except, also known as exception handling, and try-finally, also known as termination handling. The try-except statement enables applications to gain control of a program when events that normally terminate execution occur. The try-finally statement enables applications to guarantee execution of cleanup code when execution of a block of code is interrupted.

Note Structured exception handling works with Win32 for both C and C++ source files. However, it is not specifically designed for C++. You can ensure that your code is more portable by using C++ exception handling. Also, C++ exception handling is more flexible, in that it can handle exceptions of any type. For C++ programs, it is recommended that you use the new C++ exception-handling mechanism (try, catch, and throw statements).

For more general discussion, see Exception Handling: Overview.


try, catch, and throw Statements

C++ Specific —>

C++ exception handling uses the try, catch, and throw statements to implement exception handling. With C++ exception handling, your program can communicate unexpected events to a higher execution context that is better able to recover from such abnormal events. These exceptions are handled by code that is outside the normal flow of control.

Note The Win32 structured exception-handling mechanism works with both C and C++ source files. However, it is not specifically designed for C++. You can ensure that your code is more portable by using C++ exception handling. Also, C++ exception handling is more flexible, in that it can handle exceptions of any type. For C++ programs, it is recommended that you use the C++ exception-handling mechanism (try, catch, throw) described in this topic.

try-block :
try compound-statement handler-list

handler-list :
handler handler-listopt

handler :
catch ( exception-declaration ) compound-statement

exception-declaration :
type-specifier-list declarator
type-specifier-list abstract-declarator
type-specifier-list
...

throw-expression :
throw assignment-expressionopt

The compound-statement after the try clause is the guarded section of code. The throw-expression “throws” (raises) an exception. The compound-statement after the catch clause is the exception handler, and “catches” (handles) the exception thrown by the throw-expression. The exception-declaration statement indicates the type of exception the clause handles. The type can be any valid data type, including a C++ class. If the exception-declaration statement is an ellipsis (...), the catch clause handles any type of exception, including a C exception. Such a handler must be the last handler for its try-block.

The operand of throw is syntactically similar to the operand of a return statement.

Note Microsoft C++ does not support exception-specifications, as described in section 15.4 of the ANSI C++ draft. In addition, it does not support function-try-block described in section 15 of the ANSI C++ draft.

For more information on C++ exception handling, see Exception Handling Topics (C++). For information on exception handling in general, see Exception Handling: Overview.

END C++ Specific

Example

In the following example, the try block attempts to write the headers. The catch block then handles a specific file exception, and passes all other exceptions on to the outer block with the throw macro:

// Example of the try and catch statements
try
{
      // Write the file header
      file.Write((LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER));
      //
      // Write the DIB header and the bits
      file.WriteHuge(lpBI, dwDIBSize);
}
catch (CFileException* e)
   {
      ::GlobalUnlock((HGLOBAL) hDib);
      throw;
   }

::GlobalUnlock((HGLOBAL) hDib);
   return TRUE;


try-except Statement

Microsoft Specific —>

The try-except statement is a Microsoft extension to the C and C++ languages that enables 32-bit target applications to gain control when events that normally terminate program execution occur. Such events are called exceptions, and the mechanism that deals with exceptions is called structured exception handling.

For related information, see the try-finally statement. For more information on structured exception handling in general, see Exception Handling Topics (SEH).

Exceptions can be either hardware-based or software-based. Even when applications cannot completely recover from hardware or software exceptions, structured exception handling makes it possible to display error information and trap the internal state of the application to help diagnose the problem. This is especially useful for intermittent problems that cannot be reproduced easily.

Note Structured exception handling works with Win32 for both C and C++ source files. However, it is not specifically designed for C++. You can ensure that your code is more portable by using C++ exception handling. Also, C++ exception handling is more flexible, in that it can handle exceptions of any type. For C++ programs, it is recommended that you use the new C++ exception-handling mechanism (try, catch, and throw statements).

try-except-statement :
__try compound-statement
__except ( expression ) compound-statement

The compound statement after the __try clause is the body or guarded section. The compound statement after the __except clause is the exception handler. The handler specifies a set of actions to be taken if an exception is raised during execution of the body of the guarded section. Execution proceeds as follows:

  1. The guarded section is executed.

  2. If no exception occurs during execution of the guarded section, execution continues at the statement after the __except clause.

  3. If an exception occurs during execution of the guarded section or in any routine the guarded section calls, the __except expression is evaluated and the value determines how the exception is handled. There are three values:

    EXCEPTION_CONTINUE_EXECUTION (–1) Exception is dismissed. Continue execution at the point where the exception occurred.

    EXCEPTION_CONTINUE_SEARCH (0) Exception is not recognized. Continue to search up the stack for a handler, first for containing try-except statements, then for handlers with the next highest precedence.

    EXCEPTION_EXECUTE_HANDLER (1) Exception is recognized. Transfer control to the exception handler by executing the __except compound statement, then continue execution at the assembly instruction that was executing when the exception was raised.

Because the __except expression is evaluated as a C expression, it is limited to a single value, the conditional-expression operator, or the comma operator. If more extensive processing is required, the expression can call a routine that returns one of the three values listed above.

Each application can have its own exception handler. The __except expression executes in the scope of the __try body. This means it has access to any local variables declared there.

It is illegal to jump into a __try statement, but legal to jump out of one. The exception handler is not called if a process is killed in the middle of executing a try-except statement.

Structured Exception Handling Intrinsic Functions

The structured exception handling feature provides two intrinsics that are available for use with the try-except statement. These are _exception_code and _exception_info.

The intrinsic function _exception_code returns the code (a 32-bit integer) of the exception.

The intrinsic function _exception_info returns a pointer to a structure containing additional information about the exception. Through this pointer, you can access the machine state that existed at the time of a hardware exception. The structure is as follows:

struct exception_pointers {
      EXCEPTION_RECORD *ExceptionRecord,
      CONTEXT *ContextRecord }

The pointer types _EXCEPTION_RECORD and _CONTEXT are defined in the include file EXCPT.H.

You can use the _exception_code function within the exception handler. However, you can use _exception_info only within the exception filter. The information it points to is generally on the stack and is wiped out when control is transferred to the exception handler.

The intrinsic function _abnormal_termination is available within a termination handler. It returns 0 if the body of the try-finally statement terminates sequentially. In all other cases, it returns 1.

END Microsoft Specific

Example

// Example of try-except and try-finally statements
#include "stdio.h"

void main()
{
   int* p = 0x00000000;   // pointer to NULL
   puts("hello");
   try{
      puts("in try");
      try{
         puts("in try");
         *p = 13;    // causes an access violation exception;
      }__finally{
         puts("in finally");
      }
   }__except(puts("in filter"), 1){
      puts("in except");
   }
   puts("world");
}

This is the output from the example, with commentary added on the right:

hello
in try         //fall into try
in try         //fall into nested try
in filter      //execute filter; returns 1 so accept
in finally     //unwind nested finally
in except      //transfer control to selected handler
world          //flow out of handler


try-finally Statement

Microsoft Specific —>

The try-finally statement is a Microsoft extension to the C and C++ languages that enables 32-bit target applications to guarantee execution of cleanup code when execution of a block of code is interrupted. Cleanup consists of such tasks as deallocating memory, closing files, and releasing file handles. The try-finally statement is especially useful for routines that have several places where a check is made for an error that could cause premature return from the routine.

For related information, see try-except Statement. For more information on structured exception handling in general, see Exception Handling Topics (SEH).

Note Structured exception handling works with Win32 for both C and C++ source files. However, it is not specifically designed for C++. You can ensure that your code is more portable by using C++ exception handling. Also, C++ exception handling is more flexible, in that it can handle exceptions of any type. For C++ programs, it is recommended that you use the new C++ exception-handling mechanism (See try, catch, and throw statements).

try-finally-statement :
__try compound-statement
__finally compound-statement

The compound statement after the __try clause is the guarded section. The compound statement after the __finally clause is the termination handler. The handler specifies a set of actions that execute when the guarded section is exited, whether the guarded section is exited by an exception (abnormal termination), or by standard fall through (normal termination).

Control reaches a __try statement by simple sequential execution (fall through). When control enters the __try, its associated handler becomes active. Execution proceeds as follows:

  1. The guarded section is executed.

  2. The termination handler is invoked.

  3. When the termination handler completes, execution continues after the __finally statement. Regardless of how the guarded section ends (for example, via a goto out of the guarded body or a return statement), the termination handler is executed before the flow of control moves out of the guarded section.

The __leave keyword is valid within a try-finally statement block. The effect of __leave is to jump to the end of the try-finally block. The termination handler is immediately executed. Although a goto statement can be used to accomplish the same result, a goto statement causes stack unwinding. The __leave statement is more efficient because it does not involve stack unwinding.

Exiting a try-finally statement using the longjmp run-time function is considered abnormal termination. It is illegal to jump into a __try statement, but legal to jump out of one. All __finally statements that are active between the point of departure and the destination must be run. This is called a local unwind.

The termination handler is not called if a process is killed in the middle of executing a try-finally statement.

END Microsoft Specific


typedef

typedef type-declaration synonym;

The typedef keyword defines a synonym for the specified type-declaration. The identifier in the type-declaration becomes another name for the type, instead of naming an instance of the type. You cannot use the typedef specifier inside a function definition.

A typedef declaration introduces a name that, within its scope, becomes a synonym for the type given by the decl-specifiers portion of the declaration. In contrast to the class, struct, union, and enum declarations, typedef declarations do not introduce new types — they introduce new names for existing types.

Example

// Example of the typedef keyword
typedef unsigned long ulong;

ulong ul;     // Equivalent to "unsigned long ul;"

typedef struct mystructtag
{
   int   i;
   float f;
   char  c;
} mystruct;

mystruct ms;   // Equivalent to "struct mystructtag ms;"

typedef int (*funcptr)();  // funcptr is synonym for "pointer
                           //    to function returning int"

funcptr table[10];   // Equivalent to "int (*table[10])();"


typeid Operator

C++ Specific —>

typeid( type-id )

typeid( expression )

The typeid operator allows the type of an object to be determined at run-time.

The result of a typeid expression is a const type_info&. The value is a reference to a type_info object that represents either the type-id or the type of the expression, depending on which form of typeid is used. See type_info Class for more information.

END C++ Specific


typename

C++ Specific —>

typename identifier;

Use this keyword only in template definitions. This keyword tells the compiler that an unknown identifier is a type. For example:

template<class T> class X {
   typename T::Y;      // treat Y as a type

   Y m_y;
};

This keyword can also be used in place of class in template parameter lists. For example, the following statements are identical:

template<class T1, class T2>...
template<typename T1, typename T2>...

END C++ Specific


type_info Class

C++ Specific —>

The type_info class describes type information generated within the program by the compiler. Objects of this class effectively store a pointer to a name for the type and an encoded value suitable for comparing two types for equality or collating order. The encoding rules and collating sequence for types are unspecified and may differ between programs.

class type_info {
public:
   virtual ~type_info();
   int operator==(const type_info& rhs) const;
   int operator!=(const type_info& rhs) const;
   int before(const type_info& rhs) const;
   const char* name() const;
   const char* raw_name() const;
private:
   ...
};

Note You must include the typeinfo.h header file in order to use the type_info class.

END C++ Specific


union

union [tag] { member-list } [declarators];

[union] tag declarators;

The union keyword declares a union type and/or a variable of a union type.

A union is a user-defined data type that can hold values of different types at different times. It is similar to a structure except that all of its members start at the same location in memory. A union variable can contain only one of its members at a time. The size of the union is at least the size of the largest member.

For related information, see class, struct, and Anonymous Union.

Declaring a Union

Begin the declaration of a union with the union keyword, and enclose the member list in curly braces:

union UNKNOWN    // Declare union type
{
   char   ch;
   int    i;
   long   l;
   float  f;
   double d;
} var1;          // Optional declaration of union variable

Using a Union

A C++ union is a limited form of the class type. It can contain access specifiers (public, protected, private), member data, and member functions, including constructors and destructors. It cannot contain virtual functions or static data members. It cannot be used as a base class, nor can it have base classes. Default access of members in a union is public.

A C union type can contain only data members.

In C, you must use the union keyword to declare a union variable. In C++, the union keyword is unnecessary:

Example 1

union UNKNOWN var2;   // C declaration of a union variable
UNKNOWN var3;         // C++ declaration of a union variable

Example 2

A variable of a union type can hold one value of any type declared in the union. Use the member-selection operator (.) to access a member of a union:

var1.i = 6;           // Use variable as integer
var2.d = 5.327;       // Use variable as double


Anonymous Union

In C++, an anonymous union is a union without a tag or declarators; it declares an unnamed object. An anonymous union cannot have member functions or private or protected members.

A global anonymous union must be static. A local anonymous union must be either static or automatic, not external.

In C, an anonymous union can have a tag; it cannot have declarators.

The name of each member must be unique within the scope where the union is declared. You can directly access the members of an anonymous union as shown in the example.

Example

static union       // Global anonymous unions must be static
{
   int i;
   float f;
   union
   {
      char c;
      unsigned char uc;
   };
};

void my_func()
{
   i = 1;
   f = 3.14;
   c = 'c';
   uc = 'u';
};


using Declaration

C++ Specific —>

using [::] nested-name-specifier unqualified-id

using :: unqualified-id

The using declaration introduces a name into the declarative region in which the using declaration appears. The name becomes a synonym for a variable or function declared elsewhere. It allows an individual name from a specific namespace to be used without explicit qualification. This is in contrast to the using directive which allows all the names in a namespace to be used without qualification. See using Directive for related information.

END C++ Specific


using Directive

C++ Specific —>

using namespace [::] [nested-name-specifier] namespace-name

The using-directive allows the names in a namespace to be used without the namespace-name as an explicit qualifier. In contrast to a using declaration, which allows an individual name to be used without qualification, the using directive allows all the names in a namespace to be used without qualification. See using Declaration for more information.

END C++ Specific


uuid

Microsoft and C++ Specific —>

__declspec( uuid(“ComObjectGUID”) ) declarator

The compiler attaches a GUID to a class or structure declared or defined (full COM object definitions only) with the uuid attribute. The uuid attribute takes a string as its argument. This string names a GUID in normal registry format with or without the { } delimiters. For example:

struct __declspec(uuid("00000000-0000-0000-c000-000000000046")) IUnknown;
struct __declspec(uuid("{00020400-0000-0000-c000-000000000046}")) IDispatch;

This attribute can be applied in a redeclaration. This allows the system headers to supply the definitions of interfaces such as IUnknown, and the redeclaration in some other header (such as COMDEF.H) to supply the GUID.

The keyword __uuidof can be applied to retrieve the constant GUID attached to a user defined type.

END Microsoft and C++ Specific

See Also __declspec


__uuidof

Microsoft and C++ Specific —>

__uuidof ( expression )

The __uuidof keyword retrieves the GUID attached to the expression. The expression can be a type name, a pointer, reference, or array of that type, a template specialized on these types, or a variable of these types. The argument is valid as long as the compiler can use it to find the attached GUID.

A special case of this intrinsic is when either 0 or NULL is supplied as argument. In this case, __uuidof will return a GUID made up of zeros.

Use this keyword to extract the GUID attached to an object by the uuid extended attribute.

END Microsoft and C++ Specific


_variant_t

Microsoft and C++ Specific

One of the compiler COM support classes declared in COMDEF.H. It wraps the VARIANT type to provide useful operators and methods. See Compiler COM Support Classes for more information.

END Microsoft and C++ Specific


virtual

C++ Specific —>

virtual member-function-declarator

virtual [access-specifier] base-class-name

The virtual keyword declares a virtual function or a virtual base class.

The elements of a virtual declaration are as follows:

member-function-declarator

Declares a member function.

access-specifier

Defines the level of access to the base class. Can appear before or after the virtual keyword.

base-class-name

Identifies a previously declared class type.

See Virtual Function, Pure Virtual Functions and Abstract Classes, and Virtual Base Class for more information. Also see class, private, public, and protected.

END C++ Specific


Virtual Function

C++ Specific —>

A virtual function is a member function that you expect to be redefined in derived classes. When you refer to a derived class object using a pointer or a reference to the base class, you can call a virtual function for that object and execute the derived class's version of the function.

END C++ Specific

Example 1

class WageEmployee
{
public:
   virtual float computePay();
};

class SalesPerson : public WageEmployee
{
public:
   float computePay();
};

You can execute different versions of computePay( ) depending on the type of object you're calling it for.

Example 2

WageEmployee aWorker;
SalesPerson aSeller;
WageEmployee *wagePtr;

wagePtr = &aWorker;
wagePtr->computePay();   // call WageEmployee::computePay
wagePtr = &aSeller;
wagePtr->computePay();   // call SalesPerson::computePay

The virtual keyword is needed only in the base class's declaration of the function; any subsequent declarations in derived classes are virtual by default.

A derived class's version of a virtual function must have the same parameter list and return type as those of the base class. If these are different, the function is not considered a redefinition of the virtual function. A redefined virtual function cannot differ from the original only by return type.


Pure Virtual Functions and Abstract Classes

C++ Specific —>

An abstract class contains at least one pure virtual function. Specify a virtual function as pure by placing = 0 at the end of its declaration. You don't have to supply a definition for a pure virtual function.

You cannot declare an instance of an abstract base class; you can use it only as a base class when declaring other classes.

END C++ Specific

Example

In the following program, draw() is a pure virtual function defined in the abstract class Shape. You cannot declare Shape objects. Shape acts as a base class for Rectangle and Circle. Rectangle and Circle provide definitions for draw(), so you can declare instances of those classes and call draw() for them.

// Example of a virtual function and abstract classes
#include <iostream.h>

class Shape
{
public:
   virtual void draw() = 0;
};

class Rectangle: public Shape
{
public:
   void draw();
};

class Circle : public Shape
{
public:
   void draw();
};


Virtual Base Class

C++ Specific —>

Virtual base classes offer a way to save space and avoid ambiguities in class hierarchies that use multiple inheritance.

Each nonvirtual object contains a copy of the data members defined in the base class. This duplication wastes space and requires you to specify which copy of the base class members you want whenever you access them.

When a base class is specified as a virtual base, it can act as an indirect base more than once without duplication of its data members. A single copy of its data members is shared by all the base classes that use it as a virtual base.

The virtual keyword appears in the base lists of the derived classes, not the base class.

END C++ Specific


void

void declarator

When used as a function return type, the void keyword specifies that the function does not return a value. When used for a function's parameter list, void specifies that the function takes no parameters. When used in the declaration of a pointer, void specifies that the pointer is "universal."

If a pointer's type is void *, the pointer can point to any variable that is not declared with the const or volatile keyword. A void pointer cannot be dereferenced unless it is cast to another type. A void pointer can be converted into any other type of data pointer.

A void pointer can point to a function, but not to a class member in C++.

You cannot declare a variable of type void.

Example

// Examples of the void keyword
void vobject;             // Error
void *pv;                 // Okay
int  *pint; int i;
void main()               // main has no return value
{
pv = &i;
pint = (int *)pv;     // Cast optional in C
                      //     required in C++
}


volatile

volatile declarator

The volatile keyword is a type qualifier used to declare that an object can be modified in the program by something other than statements, such as the operating system, the hardware, or a concurrently executing thread.

The following example declares a volatile integer nVint whose value can be modified by external processes:

int volatile nVint;

Objects declared as volatile are not used in optimizations because their value can change at any time. The system always reads the current value of a volatile object at the point it is requested, even if the previous instruction asked for a value from the same object. Also, the value of the object is written immediately on assignment.

One use of the volatile qualifier is to provide access to memory locations used by asynchronous processes such as interrupt handlers.

For related information, see const.


while Statement

while( expression )
statement

The while keyword executes statement repeatedly until expression becomes 0.

For more information, see do, for, break, and continue.

Example

This example copies characters from string2 to string1. If i is greater than or equal to 0, string2[i] is assigned to string1[i] and i is decremented. When i reaches or falls below 0, execution of the while statement terminates.

// Example of the while statement
while ( i >= 0 )
{
    string1[i] = string2[i];
    i--;
}


C/C++ Operators

The following table lists C and C++ operators by category. Click any operator shown for more information on it.

Scope Resolution: Multiplicative: Logical:
Scope resolution: :: Multiplication: * Logical-AND: &&
Postfix: Division: / Logical-OR: ||
Array element: [ ] | Modulus: % | Assignment:
Function call: ( ) Additive: Assignment: =
Type cast: (type) Addition: + Addition: +=
Member selection: . or –> Subtraction: – Subtraction: –=
Postfix increment: ++ Shift: Multiplication: *=
Postfix decrement: –– Left shift: << Division: /=
Unary: Right shift: >> Modulus: %=
Indirection: * Relational & Equality: Left shift assignment: <<=
Address of: & Less than: < Right shift assignment: >>=
Logical-NOT: ! Less than or equal to: <= Bitwise-AND: &=
One's complement: ~ Greater than: > Bitwise-exclusive-OR: ^=
Prefix increment: ++ Greater than or equal to: >= Bitwise-inclusive-OR: |=
Prefix decrement: –– | Equal: == | Conditional:
sizeof Not equal: != Conditional: ? :
new Bitwise: Pointer to Member:
delete Bitwise-AND: & Pointer to member: .* or –>
Comma: Bitwise-exclusive-OR: ^ Reference:


Scope Resolution Operator: ::

In C++, you can tell the compiler to use the global variable rather than the local variable by prefixing the variable with ::, the scope resolution operator.

If you have nested local scopes, the scope resolution operator doesn't provide access to variables in the next outermost scope. It provides access to only the global variables.

Example

// Example of the scope resolution operator
#include <iostream.h>
int amount = 123;      // A global variable
void main()
{
    int amount = 456;    // A local variable
    cout << ::amount;    // Print the global variable
    cout << '\n';
    cout << amount;      // Print the local variable
}

The example has two variables named amount. The first is global and contains the value 123. The second is local to the main function. The two colons tell the compiler to use the global amount instead of the local one.


Postfix Operators

Click any operator below for more information on it.

Array element: [ ]
Function call: ( )
Type cast: (type)
Member selection: . or –>
Postfix increment: ++
Postfix decrement: ––


Array Element Operator: [ ]

A postfix expression followed by an expression in square brackets ([ ]) is a subscripted representation of an element of an array object. A subscript expression represents the value at the address that is expression positions beyond postfix-expression when expressed as

postfix-expression [ expression ]

Usually, the value represented by postfix-expression is a pointer value, such as an array identifier, and expression is an integral value. However, all that is required syntactically is that one of the expressions be of pointer type and the other be of integral type. Thus the integral value could be in the postfix-expression position and the pointer value could be in the brackets in the expression, or “subscript,” position.

A subscript expression can also have multiple subscripts, as follows:

expression1 [expression2] [expression3]...

Subscript expressions associate from left to right. The leftmost subscript expression, expression1[expression2], is evaluated first. The address that results from adding expression1 and expression2 forms a pointer expression; then expression3 is added to this pointer expression to form a new pointer expression, and so on until the last subscript expression has been added. The indirection operator (*) is applied after the last subscripted expression is evaluated, unless the final pointer value addresses an array type.

Expressions with multiple subscripts refer to elements of “multidimensional arrays.” A multidimensional array is an array whose elements are arrays. For example, the first element of a three-dimensional array is an array with two dimensions.

Example

The following example declares a three-dimensional array for 366 days, in each of 12 months, over a period of 10 years:

// Example of the array element operator
int nYearsMonthsDays[10][12][366];


Function Call Operator: ( )

postfix-expression :

postfix-expression ( [argument-expression-list ] )
argument-expression-list :
assignment-expression
argument-expression-list
, assignment-expression

A “function call” is an expression that includes the name of the function being called or the value of a function pointer and, optionally, the arguments being passed to the function.

The postfix-expression must evaluate to a function address (for example, a function identifier or the value of a function pointer), and argument-expression-list is a list of expressions (separated by commas) whose values (the “arguments”) are passed to the function. The argument-expression-list argument can be empty.

A function-call expression has the value and type of the function’s return value. A function cannot return an object of array type. If the function’s return type is void (that is, the function has been declared never to return a value), the function-call expression also has void type.

Example

In the following example, a function named printf is called with two parameters:

// Example of the function call operator
printf ("The number of tickets sold is %d", nNumTickets);


Type Cast Operator: (type)

cast-expression :

unary-expression
( type-name ) cast-expression

A type cast provides a method for explicit conversion of the type of an object in a specific situation.

The compiler treats cast-expression as type type-name after a type cast has been made. Casts can be used to convert objects of any scalar type to or from any other scalar type. Explicit type casts are constrained by the same rules that determine the effects of implicit conversions. Additional restraints on casts may result from the actual sizes or representation of specific types.

Example

In the following example, the type cast operator converts the float value of 3.1 to an integer value of 3.

// Example of the type cast operator
float x = 3.1;
int i;
i = (int)x;   // the value of i is now 3


Structure, Union, and Class Member Operators: . and ->

postfix-expression

. identifier

postfix-expression

–> identifier

A “member-selection expression” refers to members of structures, unions, and classes. Such an expression has the value and type of the selected member.

This list describes the two forms of the member-selection expressions:

  1. In the first form, postfix-expression represents a value of struct, class, or union type, and identifier names a member of the specified structure, union, or class. The value of the operation is that of identifier and is an l-value if postfix-expression is an l-value.

  2. In the second form, postfix-expression represents a pointer to a structure, union,or class, and identifier names a member of the specified structure, union, or class. The value is that of identifier and is an l-value.

The two forms of member-selection expressions have similar effects.

In fact, an expression involving the member-selection operator (->) is a shorthand version of an expression using the period (.) if the expression before the period consists of the indirection operator (*) applied to a pointer value. Therefore,

expression -> identifier

is equivalent to

(*expression) . identifier

when expression is a pointer value.

Example

In the following example, the structure Dates and one object, myDates, is declared. The members of the myDates object are initialized with values for the beginning of 1995.

// Example of the structure operator
struct Dates {
   CString    sGregorian;
   int      nJulian;
};
Dates myDates;
Dates.nJulian = 1;
Dates.sGregorian = "01/01/95";


Postfix Increment and Decrement Operators: ++, --

postfix-expression :

postfix-expression ++
postfix-expression --

Operands of the postfix increment and decrement operators are scalar types that are modifiable l-values.

The result of the postfix increment or decrement operation is the value of the postfix-expression before the increment or decrement operator is applied. The type of the result is the same as that of the postfix-expression but is no longer an l-value. After the result is obtained, the value of the operand is incremented (or decremented).

For more information, see Prefix Increment and Decrement Operators.

Example

In the following example, the for loop is iterated 10 times. After each iteration, the nCount variable increased by +1 using the postfix increment operator.

// Example of the postfix increment operator
for (nCount = 0; nCount < 10; nCount++) {
   nTotal += nArray[Count];
}


Unary Operators

Click any operator below for more information on it.

Indirection: *
Address of: &
Logical-NOT: !
One's complement: ~
Prefix increment: ++
Prefix decrement ––
sizeof
new
delete


Indirection Operator: *

The indirection operator (*) accesses a value indirectly, through a pointer. The operand must be a pointer value. The result of the operation is the value addressed by the operand; that is, the value at the address to which its operand points. The type of the result is the type that the operand addresses.

For related information, see Address-of Operator.

Example

In the following example, the pointer pSomething is assigned the address of nSomething. The indirection operator then assigns the value of 15 to nSomething. The result is that the variable nSomething now contains the value of 15.

// Example of the indirection operator
int nSomething;
int *pSomething;           // define pointer
pSomething = &nSomething;  // assign address
*pSomething = 15;


Address-of Operator: &

The address-of operator (&) gives the address of its operand. The operand of the address-of operator can be either a function designator or an l-value that designates an object that is not a bit field and is not declared with the register storage-class specifier.

The address-of operator can only be applied to variables with fundamental, structure, class, or union types that are declared at the file-scope level, or to subscripted array references. In these expressions, a constant expression that does not include the address-of operator can be added to or subtracted from the address expression.

For related information, see Indirection Operator.

Example

In the following example, the address-of-operator (&) takes the address of the third element of the nArray and stores the result in the pointer variable pPtr.

// Example of the address-of operator
int *pPtr;
int nArray[20];
pPtr = &nArray[2];


Logical-NOT Operator: !

The logical-negation (logical-NOT) operator produces the value 0 if its operand is true (nonzero) and the value 1 if its operand is false (0). The result has int type. The operand must be an integral, floating, or pointer value.

For more information, see logical-AND and logical-OR.

Example

In the following example, the variable EndOfJob is tested. If the value is 0, the condition is logically negated to become true (nonzero). If the value is 1, the condition is logically negated to become false (zero).

// Example of the logical-NOT operator
int EndOfJob = 0;   // 0 = not end of job, 1 = yes, end of job

if (!EndOfJob) {
   printf( "It's still not the end of job!");
}


One's Complement Operator: ~

The one's complement operator, sometimes called the "bitwise complement" or "bitwise NOT" operator, produces the bitwise one's complement of its operand. The operand must be of integral type. This operator performs usual arithmetic conversions; the result has the type of the operand after conversion.

For related information, see logical-NOT, addition, bitwise-AND, bitwise-exclusive-OR, and bitwise-inclusive-OR.

Example

In the following example, the new value assigned to y is the one's complement of the original unsigned short value:

// Example of the one's complement operator
unsigned short y = 0xAAAA;  // value of y is 0xAAAA
y = ~y;                     // value of y is 0x5555


Prefix Increment and Decrement Operators: ++, --

unary-expression :

++ unary-expression
-- unary-expression

The unary operators (++ and --) are called “prefix” increment or decrement operators when the increment or decrement operators appear before the operand. Postfix increment and decrement has higher precedence than prefix increment and decrement operators. The operand must have integral, floating, or pointer type and must be a modifiable l-value expression (an expression without the const attribute). The result is not an l-value.

When the operator appears before its operand, the operand is incremented or decremented and its new value is the result of the expression.

For more information, see Postfix Increment and Decrement Operators.

Example

In the following example, first the variable nNum2 is incremented. Then the sum of nNum1 and nNum2 is placed into nTotal.

// Example of the prefix increment operator
int nNum1=1, nNum2=2, nTotal;

nTotal = (nNum1) + (++nNum2);   // nTotal now is 4


Multiplication Operator: *

The multiplication operator (*) causes its two operands to be multiplied.

Note Since the conversions performed by the multiplicative operators do not provide for overflow or underflow conditions, information may be lost if the result of a multiplicative operation cannot be represented in the type of the operands after conversion.

Example

In the following example, nNum1 is multiplied by nNum2 giving nResult:

// Example of the multiplication operator
int nNum1=3, nNum2=4, nResult;

nResult = nNum1 * nNum2;   // nResult is now 12


Division Operator: /

The division operator ( / ) causes the first operand to be divided by the second.

Example

In the following example, nNum1 is divided by nNum2 giving nResult:

// Example of the division operator
int nNum1=10, nNum2=2, nResult;

nResult = nNum1 / nNum2;   // nResult is now 5


Modulus Operator: %

The result of the modulus operator (%) is the remainder when the first operand is divided by the second.

Example

In the following example, the modulus operator is used to determine if the numeric value 4 evenly divides into nCenturyYear. If the remainder is zero, the nCenturyYear must be a leap year, so the LeapYearFunction() is executed.

// Example of the modulus operator
int nCentury;

if ((nCenturyYear % 4) == 0) {
      LeapYearFunction();
}


Addition Operator: +

The addition operator (+) causes its two operands to be added. Both operands can be either integral or floating types, or one operand can be a pointer and the other an integer.

For more information, see logical-NOT, subtraction, and one's complement.

Example

In the following example, two integers nNumA and nNumB are added together to give result nNumC:

// Example of the addition operator
int nNumA=1, nNumB=2, nNumC;

nNumC = nNumA + nNumB;    // nNumC is now 3


Subtraction Operator: -

The subtraction operator (-) subtracts the second operand from the first. Both operands can be either integral or floating types, or one operand can be a pointer and the other an integer.

For more information, see logical-NOT, addition, and one's complement.

Example

In the following example, integer nNumB is subtracted from integer nNumA giving result nNumC:

// Example of the subtraction operator
int nNumA=8, nNumB=2, nNumC;

nNumC = nNumA - nNumB;    // nNumC is now 6


Bitwise Left Shift and Right Shift Operators: <<, >>

shift-expression :

additive-expression
shift-expression << additive-expression
shift-expression >> additive-expression

The bitwise shift operators shift their first operand left (<<) or right (>>) by the number of positions the second operand specifies.

For more information, see bitwise-AND, bitwise-exclusive-OR, bitwise-inclusive-OR, and one's complement.

Example

In the following example, the right shift operator moves the data bits two positions to the right, thus changing the value of nNumA:

// Example of the bitwise right shift operator
int nNumA=8;    // beginning value is 8

nNumA >> 2;     // ending value is 2


Relational and Equality Operators: <, <=, >, >=, ==, !=

The binary relational and equality operators compare their first operand to their second operand to test the validity of the specified relationship. The result of a relational expression is 1 if the tested relationship is true and 0 if it is false. The type of the result is int.

Example

In the following example, two integers are tested for inequality:

// Example of the inequality operator
int nNumA=1, nNumB=2;

if (nNumA != nNumB) {  // it's true: the operands are not equal
    AnyFunction();     // therefore, this function is executed
}


Bitwise-AND Operator: &

AND-expression :

relational-expression
AND-expression & equality-expression

The bitwise-AND operator (&) compares each bit of its first operand to the corresponding bit of its second operand. If both bits are 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.

Example

In the following example, the bitwise-AND operator (&) compares the bits of two integers, nNumA and nNumB:

// Example of the bitwise-AND operator
int nNumA=1, nNumB=3, nNumC; // 00000001, 00000011

nNumC = nNumA & nNumB;       // nNumC is now 1

For related information, see bitwise-exclusive-OR, bitwise-inclusive-OR, shift operators, and one's complement.


Bitwise-Exclusive-OR Operator: ^

exclusive-OR-expression :

AND-expression
exclusive-OR-expression ^ AND-expression

The bitwise-exclusive-OR operator (^) compares each bit of its first operand to the corresponding bit of its second operand. If one bit is 0 and the other bit is 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.

Example

In the following example, the bitwise-exclusive-OR operator (^) compares the bits of two integers, nNumA and nNumB:

// Example of the bitwise-exclusive-OR operator
int nNumA=9, nNumB=3, nNumC; // 00001001, 00000011

nNumC = nNumA ^ nNumB;       // nNumC is now 10: 00001010

For related information, see bitwise-AND, bitwise-inclusive-OR, shift operators, and one's complement.


Bitwise-Inclusive-OR Operator: |

inclusive-OR-expression :

exclusive-OR-expression
inclusive-OR-expression | exclusive-OR-expression

The bitwise-inclusive-OR operator (|) compares each bit of its first operand to the corresponding bit of its second operand. If either bit is 1, the corresponding result bit is set to 1. Otherwise, the corresponding result bit is set to 0.

Example

In the following example, the bitwise-inclusive-OR operator (|) compares the bits of two integers, nNumA and nNumB:

// Example of the bitwise-inclusive-OR operator
int nNumA=9, nNumB=3, nNumC; // 00001001, 00000011

nNumC = nNumA | nNumB;       // nNumC is now 11: 00001011

For related information, see bitwise-AND, bitwise-exclusive-OR, shift operators, and one's complement.


Logical-AND Operator: &&

logical-AND-expression :

inclusive-OR-expression
logical-AND-expression && inclusive-OR-expression

The logical operators, logical-AND (&&) and logical-OR (||), are used to combine multiple conditions formed using relational or equality expressions. The logical-AND operator returns the integral value 1 if both operands are nonzero; otherwise, it returns 0. Logical-AND has left-to-right associativity.

Example

In the following example, the logical-AND operator (&&) determines if the account balance is 0 (true) and also if the account is at least three years old (false). Since they are not both true, the ExtendAccount function is not executed.

// Example of the logical-AND operator
int nAccountBalance=0, nAccountYears=1;

if ((nAccountBalance == 0) && (nAccountYears > 3)) {
     ExtendAccount();     // so, this function will not execute
}

For related information, see logical-OR and logical-NOT.


Logical-OR Operator: ||

logical-OR-expression :

logical-AND-expression
logical-OR-expression || logical-AND-expression

The logical operators, logical-AND (&&) and logical-OR (||), are used to combine multiple conditions formed using relational or equality expressions. The logical-OR operator (||) returns the integral value 1 if either operand is nonzero; otherwise, it returns 0. Logical-OR has left-to-right associativity.

Example

In the following example, the logical-OR operator (||) determines if either switch setting is true. Since nSw1 is true, AnyFunction() will execute.

// Example of the logical-OR operator
int nSw1=1, nSw2=0;

if (nSw1 || nSw2) {  // nSw1 is true while nSw2 is not true
     AnyFunction();  //  so, this function will execute
}

For related information, see logical-AND and logical-NOT.


Assignment Operators: =, +=, -=, *=, /=, %=, >>=, <<=, &=, ^=, |=

assignment-expression :

conditional-expression
unary-expression assignment-operator assignment-expression

An assignment operation assigns the value of the right-hand operand to the storage location named by the left-hand operand. Therefore, the left-hand operand of an assignment operation must be a modifiable l-value. After the assignment, an assignment expression has the value of the left operand but is not an l-value. The assignment-operator is one of the following:

Operator | Operation Performed
= | Simple assignment
*= | Multiplication assignment
/= | Division assignment
%= | Remainder assignment
+= | Addition assignment
-= | Subtraction assignment
<<= | Left-shift assignment
>>= | Right-shift assignment
&= | Bitwise-AND assignment
|= | Bitwise-inclusive-OR assignment
^= | Bitwise-exclusive-OR assignment

Example

In the following example, the addition assignment operator (+=) is used to add 3 to nNumber:

// Example of the addition assignment operator
int nNumber=1;

nNumber += 3;    // nNumber now is 4


Comma Operator: ,

expression :

assignment-expression
expression , assignment-expression

The comma operator, also called the “sequential-evaluation” operator, evaluates its two operands sequentially from left to right.

The left operand of the comma operator is evaluated as a void expression. The result of the operation has the same value and type as the right operand. Each operand can be of any type. The comma operator does not perform type conversions between its operands, and it does not yield an l-value. There is a sequence point after the first operand, which means all side effects from the evaluation of the left operand are completed before beginning evaluation of the right operand.

The comma operator is typically used to evaluate two or more expressions in contexts where only one expression is allowed.

Commas can be used as separators in some contexts. However, you must be careful not to confuse the use of the comma as a separator with its use as an operator; the two uses are completely different.

Example

In the following example, the function AnyFunction has three arguments, with the second argument resolving to a value of 3.

// Example of the comma operator
AnyFunction(a, (b=1, b+2), c);


Conditional Operator: ? :

conditional expression :

logical-OR-expression
logical-OR-expression ? expression : conditional-expression

The conditional operator is a ternary operator (it takes three operands).

The logical-OR-expression must have integral, floating, or pointer type. It is evaluated in terms of its equivalence to 0. A sequence point follows logical-OR-expression.

Note that either expression or conditional-expression is evaluated, but not both.

In the type comparison for pointers, any type qualifiers (const or volatile) in the type to which the pointer points are insignificant, but the result type inherits the qualifiers from both components of the conditional.

Example

In the following example, nAcctBal is checked to see if it is below zero. If so, nTotalDue is set to zero. If not, nTotalDue is set to the value in nAcctBal.

// Example of the conditional operator
int nTotalDue, nAcctBal=200;

nTotalDue = (nAcctBal < 0) ? 0 : nAcctBal;   // nTotalDue now is 200


Pointer to Member Operators: .* and ->*

pm-expression :

cast-expression
pm-expression .* cast-expression
pm-expression ->* cast-expression

The binary operator .* combines its first operand, which must be an object of class type, with its second operand, which must be a pointer-to-member type.

The binary operator ->* combines its first operand, which must be a pointer to an object of class type, with its second operand, which must be a pointer-to-member type.

In an expression containing the .* operator, the first operand must be of the class type of the pointer to member specified in the second operand or of a type unambiguously derived from that class.

In an expression containing the ->* operator, the first operand must be of the type "pointer to the class type" of the type specified in the second operand, or it must be of a type unambiguously derived from that class.

Example

The following example calls the member function designated by pMemberFunc for the object pointed to by pObject and passes the parameter of 6:

// Example of the pointer to member operators
(pObject->*pMemberFunc) (6);


Reference Operator: &

decl-specifiers & cv-qualifier-listopt dname ;

A reference is a 16-bit or 32-bit quantity that holds the address of an object but behaves syntactically like that object. A reference declaration consists of an (optional) list of specifiers followed by a reference declarator.

In C++, any object whose address can be converted to a given pointer type can also be converted to the analogous reference type. For example, any object whose address can be converted to type char * can also be converted to type char &. No constructors or class conversion functions are called to make a conversion to a reference type.

Example

In the following example, the variable x is passed by reference and modified by the AddIt function.

// Example of the reference operator
void AddIt(int& x)
{
      x += 2;
}

int x;

x = 3;
AddIt(x);
printf("%d, x) ;   // the value of x is now 5


Reference Tables

The following tables list useful reference information:

  • Data Type Ranges

  • Operator Precedence and Associativity

  • Escape Sequences

  • ASCII Character Codes

  • Key Scan Codes


Data Type Ranges

C/C++ recognizes the types shown in the table below.

Type Name | Bytes | Other Names | Range of Values
int | * | signed, signed int | System dependent
unsigned int | * | unsigned | System dependent
__int8 | 1 | char, signed char | –128 to 127
__int16 | 2 | short, short int, signed short int | –32,768 to 32,767
__int32 | 4 | signed, signed int | –2,147,483,648 to 2,147,483,647
__int64 | 8 | none | –9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
char | 1 | signed char | –128 to 127
unsigned char | 1 | none | 0 to 255
short | 2 | short int, signed short int | –32,768 to 32,767
unsigned short | 2 | unsigned short int | 0 to 65,535
long | 4 | long int, signed long int | –2,147,483,648 to 2,147,483,647
unsigned long | 4 | unsigned long int | 0 to 4,294,967,295
enum | * | none | Same as int
float | 4 | none | 3.4E +/- 38 (7 digits)
double | 8 | none | 1.7E +/- 308 (15 digits)
long double | 10 | none | 1.2E +/- 4932 (19 digits)

The long double data type (80-bit, 10-byte precision) is mapped directly to double (64-bit, 8- byte precision) in Windows NT and Windows 95.

Signed and unsigned are modifiers that can be used with any integral type. The char type is signed by default, but you can specify /J to make it unsigned by default.

The int and unsigned int types have the size of the system word. This is two bytes (the same as short and unsigned short) in MS-DOS and 16-bit versions of Windows, and 4 bytes in 32-bit operating systems. However, portable code should not depend on the size of int.

Microsoft C/C++ also features support for sized integer types. See __int8, __int16, __int32, __int64 for more information. Also see Integer Limits.


Operator Precedence and Associativity

The table below lists the C and C++ operators and their precedence and associativity values. The highest precedence level is at the top of the table.

Symbol | Name or Meaning | Associativity
 | Highest Precedence |
++ | Post-increment | Left to right
-- | Post-decrement |
( ) | Function call |
[ ] | Array element |
-> | Pointer to structure member |
. | Structure or union member |
++ | Pre-increment | Right to left
-- | Pre-decrement |
! | Logical NOT |
~ | Bitwise NOT |
- | Unary minus |
+ | Unary plus |
& | Address |
* | Indirection |
sizeof | Size in bytes |
new | Allocate program memory |
delete | Deallocate program memory |
(type) | Type cast [for example, (float) i] |
.* | Pointer to member (objects) | Left to right
->* | Pointer to member (pointers) |
* | Multiply | Left to right
/ | Divide |
% | Remainder |
+ | Add | Left to right
- | Subtract |
<< | Left shift | Left to right
>> | Right shift |
< | Less than | Left to right
<= | Less than or equal to |
> | Greater than |
>= | Greater than or equal to |
== | Equal | Left to right
!= | Not equal |
& | Bitwise AND | Left to right
^ | Bitwise exclusive OR | Left to right
| | Bitwise OR | Left to right
&& | Logical AND | Left to right
|| | Logical OR | Left to right
? : | Conditional | Right to left
= | Assignment | Right to left
*=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= | Compound assignment |
, | Comma | Left to right
 | Lowest Precedence |


Escape Sequences

The escape sequences allow you to use a sequence of characters to represent special characters. Escape sequences are listed below.

Sequence | Name
\a | Alert (bell)
\b | Backspace
\f | Formfeed
\n | Newline
\r | Carriage return
\t | Horizontal tab
\v | Vertical tab
\? | Literal quotation mark
\' | Single quotation mark
\" | Double quotation mark
\\ | Backslash
\ddd | ASCII character in octal notation
\xdd | ASCII character in hex notation
\0 | Null character

Note that for characters notated in hexadecimal, the compiler ignores all leading zeros. It establishes the end of the hex-specified escape character when it encounters either the first non-hex character or more than two hex characters — not including leading zeros. In the latter case, it reports an error and ignores all characters beyond the second one.


ASCII Character Codes


Key Scan Codes


Run-Time Library Reference

The Microsoft run-time library provides routines for programming for the Microsoft Windows NT and Windows 95 operating systems. These routines automate many common programming tasks that are not provided by the C and C++ languages.
C Run-Time Libraries
Run-time routines listed by category
Global variables
Standard types
Global constants

Interesting home pages
Visual C++ Home The entire Visual C++ product.
Microsoft Foundation Class Library MFC Reference and Tech Notes.
Compiling and Linking Building your program.
C++ Standard Library Includes the Standard Template Library and revised iostream classes.
iostream Class Library Original iostream classes.


C Run-Time Libraries

The following table lists the release versions of the C run-time library files, along with their associated compiler options and environment variables. Prior to Visual C++ 4.2, the C run-time libraries contained the iostream library functions. In Visual C++ 4.2 and later, the old iostream library functions have been removed from LIBC.LIB, LIBCMT.LIB, and MSVCRT.LIB. (This change was made because the Standard C++ library has been added to Visual C++, and it contains a new set of iostream libraries. Thus, two sets of iostream functions are now included in Visual C++.) The old iostream functions now exist in their own libraries: LIBCI.LIB, LIBCIMT.LIB, and MSVCIRT.LIB. The new iostream functions, as well as many other new functions, exist in the Standard C++ libraries: LIBCP.LIB, LIBCPMT.LIB, and MSVCPRT.LIB.

The Standard C++ library and the old iostream library are incompatible, and only one of them can be linked with your project. See Port to the Standard C++ Library and the Standard C++ Library Overview for details.

When you build a release version of your project, one of the basic C run-time libraries (LIBC.LIB, LIBCMT.LIB, and MSVCRT.LIB) is linked by default, depending on the compiler option you choose (single-threaded, multithreaded, or DLL). Depending on the headers you use in your code, a library from the Standard C++ libraries or one from the old iostream libraries may also be linked:

  • If you include a Standard C++ library header in your code, a Standard C++ library will be linked in automatically by Visual C++ at compile time. For example:
   #include <ios>
  • If you include an old iostream library header, an old iostream library will be linked in automatically by Visual C++ at compile time. For example:
   #include <ios.h>

Note that headers from the Standard C++ library and the old iostream library cannot be mixed.

Headers determine whether a Standard C++ library, an old iostream library, or neither will be linked. Compiler options determine which of the libraries to be linked is the default (single-threaded, multithreaded, or DLL). When a specific library compiler option is defined, that library is considered to be the default and its environment variables are automatically defined.

C Run-Time Library (without iostream) | Characteristics | Option | Defined
LIBC.LIB | Single threaded, static link | /ML |
LIBCMT.LIB | Multithreaded, static link | /MT | _MT
MSVCRT.LIB | Multithreaded, dynamic link (import library for MSVCRT.DLL) | /MD | _MT, _DLL

Standard C++ Library | Characteristics | Option | Defined
LIBCP.LIB | Single threaded, static link | /ML |
LIBCPMT.LIB | Multithreaded, static link | /MT | _MT
MSVCPRT.LIB | Multithreaded, dynamic link (import library for MSVCRT.DLL) | /MD | _MT, _DLL

Old Iostream Library | Characteristics | Option | Defined
LIBCI.LIB | Single threaded, static link | /ML |
LIBCIMT.LIB | Multithreaded, static link | /MT | _MT
MSVCIRT.LIB | Multithreaded, dynamic link (import library for MSVCIRT.DLL) | /MD | _MT, _DLL

To build a debug version of your application, the _DEBUG flag must be defined and the application must be linked with a debug version of one of these libraries. For more information about using the debug versions of the library files, see C Run-Time Debug Libraries.


Building the Run-Time Libraries

There are two batch files provided for building the C run-time libraries from the source code included with Visual C++:

  • \Microsoft Visual Studio\VC98\CRT\SRC\BLDWIN95.BAT, used when building on Windows 95

  • \Microsoft Visual Studio\VC98\CRT\SRC\BLDNT.CMD, used when building on Windows NT

When using either BLDNT.CMD or BLDWIN95.BAT, set the V5TOOLS environment variable to the root of the Visual C++ installation (such as C:\Microsoft Visual Studio\VC98\Bin). If this environment variable is not set, an error message will be displayed and the batch file will exit.


Compatibility

The Microsoft run-time library supports American National Standards Institute (ANSI) C and UNIX® C. In this book, references to UNIX include XENIX®, other UNIX-like systems, and the POSIX subsystem in Windows NT and Windows 95. The description of each run-time library routine in this book includes a compatibility section for these targets: ANSI, Windows 95 (listed as Win 95), and Windows NT (Win NT). All run-time library routines included with this product are compatible with the Win32 API.


ANSI C Compliance

The naming convention for all Microsoft-specific identifiers in the run-time system (such as functions, macros, constants, variables, and type definitions) is ANSI-compliant. In this book, any run-time function that follows the ANSI/ISO C standards is noted as being ANSI compatible. ANSI-compliant applications should only use these ANSI compatible functions.

The names of Microsoft-specific functions and global variables begin with a single underscore. These names can be overridden only locally, within the scope of your code. For example, when you include Microsoft run-time header files, you can still locally override the Microsoft-specific function named _open by declaring a local variable of the same name. However, you cannot use this name for your own global function or global variable.

The names of Microsoft-specific macros and manifest constants begin with two underscores, or with a single leading underscore immediately followed by an uppercase letter. The scope of these identifiers is absolute. For example, you cannot use the Microsoft-specific identifier _UPPER for this reason.


UNIX

If you plan to transport your programs to UNIX, follow these guidelines:

  • Do not remove header files from the SYS subdirectory. You can place the SYS header files elsewhere only if you do not plan to transport your programs to UNIX.

  • Use the UNIX-compatible path delimiter in routines that take strings representing paths and filenames as arguments. UNIX supports only the forward slash (/) for this purpose, whereas Win32 operating systems support both the backslash (\) and the forward slash (/). Thus this book uses UNIX-compatible forward slashes as path delimiters in #include statements, for example. (However, the Windows NT and Windows 95 command shell, CMD.EXE, does not support the forward slash in commands entered at the command prompt.)

  • Use paths and filenames that work correctly in UNIX, which is case sensitive. The file allocation table (FAT) file system in Win32 operating systems is not case sensitive; the installable Windows NT file system (NTFS) of Windows NT preserves case for directory listings but ignores case in file searches and other system operations.

Note In this version of Visual C++, UNIX compatibility information has been removed from the function descriptions.


Win32 Platforms

The C run-time libraries support Windows 95 and Windows NT, but not Win32s. Windows 95 and Windows NT support the Win32 Application Programming Interface (API), but only Windows NT provides full Unicode support. In addition, any Win32 application can use a multibyte character set (MBCS).


Backward Compatibility

The compiler views a structure that has both an old name and a new name as two different types. You cannot copy from an old structure type to a new structure type. Old prototypes that take struct pointers use the old struct names in the prototype.

For compatibility with Microsoft C professional development system version 6.0 and earlier Microsoft C versions, the library OLDNAMES.LIB maps old names to new names. For instance, open maps to _open. You must explicitly link with OLDNAMES.LIB only when you compile with the following combinations of command-line options:

  • /Zl (omit default library name from object file) and /Ze (the default — use Microsoft extensions)

  • /link (linker-control), /NOD (no default-library search), and /Ze

For more information about compiler command-line options, see Compiler Reference in the Visual C++ Programmer’s Guide.


Required and Optional Header Files

The description of each run-time routine in this book includes a list of the required and optional include, or header (.H), files for that routine. Required header files need to be included to obtain the function declaration for the routine or a definition used by another routine called internally. Optional header files are usually included to take advantage of predefined constants, type definitions, or inline macros. The following table lists some examples of optional header file contents:

Definition | Example
Macro definition | If a library routine is implemented as a macro, the macro definition may be in a header file other than the header file for the original routine. For instance, the toupper macro is defined in the header file CTYPE.H, while the function toupper is declared in STDLIB.H.
Manifest constant | Many library routines refer to constants that are defined in header files. For instance, the _open routine uses constants such as _O_CREAT, which is defined in the header file FCNTL.H.
Type definition | Some library routines return a structure or take a structure as an argument. For example, stream input/output routines use a structure of type FILE, which is defined in STDIO.H.

The run-time library header files provide function declarations in the ANSI/ISO C standard recommended style. The compiler performs “type checking” on any routine reference that occurs after its associated function declaration. Function declarations are especially important for routines that return a value of some type other than int, which is the default. Routines that do not specify their appropriate return value in their declaration will be considered by the compiler to return an int, which can cause unexpected results. See Type Checking for more information.


Choosing Between Functions and Macros

Most Microsoft run-time library routines are compiled or assembled functions, but some routines are implemented as macros. When a header file declares both a function and a macro version of a routine, the macro definition takes precedence, because it always appears after the function declaration. When you invoke a routine that is implemented as both a function and a macro, you can force the compiler to use the function version in two ways:

  • Enclose the routine name in parentheses.
    #include <ctype.h>
a = toupper(a);    //use macro version of toupper
a = (toupper)(a);  //force compiler to use function version of toupper
  • “Undefine” the macro definition with the #undef directive:
    #include <ctype.h>
#undef toupper

If you need to choose between a function and a macro implementation of a library routine, consider the following trade-offs:

  • Speed versus size. The main benefit of using macros is faster execution time. During preprocessing, a macro is expanded (replaced by its definition) inline each time it is used. A function definition occurs only once regardless of how many times it is called. Macros may increase code size but do not have the overhead associated with function calls.

  • Function evaluation. A function evaluates to an address; a macro does not. Thus you cannot use a macro name in contexts requiring a pointer. For instance, you can declare a pointer to a function, but not a pointer to a macro.

  • Macro side effects. A macro may treat arguments incorrectly when the macro evaluates its arguments more than once. For instance, the toupper macro is defined as:
    #define toupper(c) ( (islower(c)) ? _toupper(c) :  (c) )

    In the following example, the toupper macro produces a side effect:

    #include <ctype.h>

int a = 'm';
a = toupper(a++);

    The example code increments a when passing it to toupper. The macro evaluates the argument a++ twice, once to check case and again for the result, therefore increasing a by 2 instead of 1. As a result, the value operated on by islower differs from the value operated on by toupper.

  • Type-checking. When you declare a function, the compiler can check the argument types. Because you cannot declare a macro, the compiler cannot check macro argument types, although it can check the number of arguments you pass to a macro.


Type Checking

The compiler performs limited type checking on functions that can take a variable number of arguments, as follows:

Function Call | Type-Checked Arguments
_cprintf, _cscanf, printf, scanf | First argument (format string)
fprintf, fscanf, sprintf, sscanf | First two arguments (file or buffer and format string)
_snprintf | First three arguments (file or buffer, count, and format string)
_open | First two arguments (path and _open flag)
_sopen | First three arguments (path, _open flag, and sharing mode)
_execl, _execle, _execlp, _execlpe | First two arguments (path and first argument pointer)
_spawnl, _spawnle, _spawnlp, _spawnlpe | First three arguments (mode flag, path, and first argument pointer)

The compiler performs the same limited type checking on the wide-character counterparts of these functions.


Run-Time Routines by Category

This chapter lists and describes Microsoft run-time library routines by category. For reference convenience, some routines are listed in more than one category. Multibyte-character routines and wide-character routines are grouped with single-byte – character counterparts, where they exist.

The main categories of Microsoft run-time library routines are:

Argument access | Floating-point support
Buffer manipulation | Input and output
Byte classification | Internationalization
Character classification | Memory allocation
Data conversion | Process and environment control
Debug | Searching and sorting
Directory control | String manipulation
Error handling | System calls
Exception handling | Time management
File handling |


Argument Access

The va_arg, va_end, and va_start macros provide access to function arguments when the number of arguments is variable. These macros are defined in STDARG.H for ANSI C compatibility, and in VARARGS.H for compatibility with UNIX System V.

Argument-Access Macros

Macro | Use
va_arg | Retrieve argument from list
va_end | Reset pointer
va_start | Set pointer to beginning of argument list


Buffer Manipulation

Use these routines to work with areas of memory on a byte-by-byte basis.

Buffer-Manipulation Routines

Routine | Use
_memccpy | Copy characters from one buffer to another until given character or given number of characters has been copied
memchr | Return pointer to first occurrence, within specified number of characters, of given character in buffer
memcmp | Compare specified number of characters from two buffers
memcpy | Copy specified number of characters from one buffer to another
_memicmp | Compare specified number of characters from two buffers without regard to case
memmove | Copy specified number of characters from one buffer to another
memset | Use given character to initialize specified number of bytes in the buffer
_swab | Swap bytes of data and store them at specified location

When the source and target areas overlap, only memmove is guaranteed to copy the full source properly.


Byte Classification

Each of these routines tests a specified byte of a multibyte character for satisfaction of a condition. Except where specified otherwise, the test result depends on the multibyte code page currently in use.

Note By definition, the ASCII character set is a subset of all multibyte-character sets. For example, the Japanese katakana character set includes ASCII as well as non-ASCII characters.

The manifest constants in the following table are defined in CTYPE.H:

Multibyte-Character Byte-Classification Routines

Routine | Byte Test Condition
isleadbyte | Lead byte; test result depends on LC_CTYPE category setting of current locale
_ismbbalnum | isalnum || _ismbbkalnum
_ismbbalpha | isalpha || _ismbbkalnum
_ismbbgraph | Same as _ismbbprint, but _ismbbgraph does not include the space character (0x20)
_ismbbkalnum | Non-ASCII text symbol other than punctuation. For example, in code page 932 only, _ismbbkalnum tests for katakana alphanumeric
_ismbbkana | Katakana (0xA1 – 0xDF), code page 932 only
_ismbbkprint | Non-ASCII text or non-ASCII punctuation symbol. For example, in code page 932 only, _ismbbkprint tests for katakana alphanumeric or katakana punctuation (range: 0xA1 – 0xDF).
_ismbbkpunct | Non-ASCII punctuation. For example, in code page 932 only, _ismbbkpunct tests for katakana punctuation.
_ismbblead | First byte of multibyte character. For example, in code page 932 only, valid ranges are 0x81 – 0x9F, 0xE0 – 0xFC.
_ismbbprint | isprint || _ismbbkprint. ismbbprint includes the space character (0x20)
_ismbbpunct | ispunct || _ismbbkpunct
_ismbbtrail | Second byte of multibyte character. For example, in code page 932 only, valid ranges are 0x40 – 0x7E, 0x80 – 0xEC.
_ismbslead | Lead byte (in string context)
_ismbstrail | Trail byte (in string context)
_mbbtype | Return byte type based on previous byte
_mbsbtype | Return type of byte within string

The MB_LEN_MAX macro, defined in LIMITS.H, expands to the maximum length in bytes that any multibyte character can have. MB_CUR_MAX, defined in STDLIB.H, expands to the maximum length in bytes of any multibyte character in the current locale.


Character Classification

Each of these routines tests a specified single-byte character, wide character, or multibyte character for satisfaction of a condition. (By definition, the ASCII character set is a subset of all multibyte-character sets. For example, Japanese katakana includes ASCII as well as non-ASCII characters.) Generally these routines execute faster than tests you might write. For example, the following code executes slower than a call to isalpha(c):

if ((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))
    return TRUE;

Character-Classification Routines

Routine | Character Test Condition
isalnum, iswalnum, _ismbcalnum | Alphanumeric
isalpha, iswalpha, _ismbcalpha | Alphabetic
__isascii, iswascii | ASCII
iscntrl, iswcntrl | Control
__iscsym | Letter, underscore, or digit
__iscsymf | Letter or underscore
isdigit, iswdigit, _ismbcdigit | Decimal digit
isgraph, iswgraph, _ismbcgraph | Printable other than space
islower, iswlower, _ismbclower | Lowercase
_ismbchira | Hiragana
_ismbckata | Katakana
_ismbclegal | Legal multibyte character
_ismbcl0 | Japan-level 0 multibyte character
_ismbcl1 | Japan-level 1 multibyte character
_ismbcl2 | Japan-level 2 multibyte character
_ismbcsymbol | Non-alphanumeric multibyte character
isprint, iswprint, _ismbcprint | Printable
ispunct, iswpunct, _ismbcpunct | Punctuation
isspace, iswspace, _ismbcspace | White-space
isupper, iswupper, _ismbcupper | Uppercase
iswctype | Property specified by desc argument
isxdigit, iswxdigit | Hexadecimal digit
mblen | Return length of valid multibyte character; result depends on LC_CTYPE category setting of current locale


Data Conversion

These routines convert data from one form to another. Generally these routines execute faster than conversions you might write. Each routine that begins with a to prefix is implemented as a function and as a macro. See Choosing Between Functions and Macros for information about choosing an implementation.

Data-Conversion Routines

Routine | Use
abs | Find absolute value of integer
atof | Convert string to float
atoi, _atoi64 | Convert string to int
atol | Convert string to long
_ecvt | Convert double to string of specified length
_fcvt | Convert double to string with specified number of digits following decimal point
_gcvt | Convert double number to string; store string in buffer
_itoa, _i64toa, _itow, _i64tow | Convert int to string
labs | Find absolute value of long integer
_ltoa, _ltow | Convert long to string
_mbbtombc | Convert 1-byte multibyte character to corresponding 2-byte multibyte character
_mbcjistojms | Convert Japan Industry Standard (JIS) character to Japan Microsoft (JMS) character
_mbcjmstojis | Convert JMS character to JIS character
_mbctohira | Convert multibyte character to 1-byte hiragana code
_mbctokata | Convert multibyte character to 1-byte katakana code
_mbctombb | Convert 2-byte multibyte character to corresponding 1-byte multibyte character
mbstowcs | Convert sequence of multibyte characters to corresponding sequence of wide characters
mbtowc | Convert multibyte character to corresponding wide character
strtod, wcstod | Convert string to double
strtol, wcstol | Convert string to long integer
strtoul, wcstoul | Convert string to unsigned long integer
strxfrm, wcsxfrm | Transform string into collated form based on locale-specific information
__toascii | Convert character to ASCII code
tolower, towlower, _mbctolower | Test character and convert to lowercase if currently uppercase
_tolower | Convert character to lowercase unconditionally
toupper, towupper, _mbctoupper | Test character and convert to uppercase if currently lowercase
_toupper | Convert character to uppercase unconditionally
_ultoa, _ultow | Convert unsigned long to string
wcstombs | Convert sequence of wide characters to corresponding sequence of multibyte characters
wctomb | Convert wide character to corresponding multibyte character
_wtoi | Convert wide-character string to int
_wtol | Convert wide-character string to long


Debug Routines

With this version, Visual C++ introduces debug support for the C run-time library. The new debug version of the library supplies many diagnostic services that make debugging programs easier and allow developers to:

  • Step directly into run-time functions during debugging

  • Resolve assertions, errors, and exceptions

  • Trace heap allocations and prevent memory leaks

  • Report debug messages to the user

To use these routines, the _DEBUG flag must be defined. All of these routines do nothing in a retail build of an application. For more information on how to use the new debug routines, see Using C Run-Time Library Debugging Support.

Debug Versions of the C Run-time Library Routines

Routine | Use
_ASSERT | Evaluate an expression and generates a debug report when the result is FALSE
_ASSERTE | Similar to _ASSERT, but includes the failed expression in the generated report
_CrtCheckMemory | Confirm the integrity of the memory blocks allocated on the debug heap
_CrtDbgReport | Generate a debug report with a user message and send the report to three possible destinations
_CrtDoForAllClientObjects | Call an application-supplied function for all _CLIENT_BLOCK types on the heap
_CrtDumpMemoryLeaks | Dump all of the memory blocks on the debug heap when a significant memory leak has occurred
_CrtIsValidHeapPointer | Verify that a specified pointer is in the local heap
_CrtIsMemoryBlock | Verify that a specified memory block is located within the local heap and that it has a valid debug heap block type identifier
_CrtIsValidPointer | Verify that a specified memory range is valid for reading and writing
_CrtMemCheckpoint | Obtain the current state of the debug heap and store it in an application-supplied _CrtMemState structure
_CrtMemDifference | Compare two memory states for significant differences and return the results
_CrtMemDumpAllObjectsSince | Dump information about objects on the heap since a specified checkpoint was taken or from the start of program execution
_CrtMemDumpStatistics | Dump the debug header information for a specified memory state in a user-readable form
_CrtSetAllocHook | Install a client-defined allocation function by hooking it into the C run-time debug memory allocation process
_CrtSetBreakAlloc | Set a breakpoint on a specified object allocation order number
_CrtSetDbgFlag | Retrieve or modify the state of the _crtDbgFlag flag to control the allocation behavior of the debug heap manager
_CrtSetDumpClient | Install an application-defined function that is called every time a debug dump function is called to dump _CLIENT_BLOCK type memory blocks
_CrtSetReportFile | Identify the file or stream to be used as a destination for a specific report type by _CrtDbgReport
_CrtSetReportHook | Install a client-defined reporting function by hooking it into the C run-time debug reporting process
_CrtSetReportMode | Specify the general destination(s) for a specific report type generated by _CrtDbgReport
_RPT[0,1,2,3,4] | Track the application’s progress by generating a debug report by calling _CrtDbgReport with a format string and a variable number of arguments. Provides no source file and line number information.
_RPTF[0,1,2,3,4] | Similar to the _RPTn macros, but provides the source file name and line number where the report request originated
_calloc_dbg | Allocate a specified number of memory blocks on the heap with additional space for a debugging header and overwrite buffers
_expand_dbg | Resize a specified block of memory on the heap by expanding or contracting the block
_free_dbg | Free a block of memory on the heap
_malloc_dbg | Allocate a block of memory on the heap with additional space for a debugging header and overwrite buffers
_msize_dbg | Calculate the size of a block of memory on the heap
_realloc_dbg | Reallocate a specified block of memory on the heap by moving and/or resizing the block

The debug routines can be used to step through the source code for most of the other C run-time routines during the debugging process. However, Microsoft considers some technology to be proprietary and, therefore, does not provide the source code for these routines. Most of these routines belong to either the exception handling or floating-point processing groups, but a few others are included as well. The following table lists these routines.

C Run-time Routines that are Not Available in Source Code Form

acos | _fpclass | _nextafter
asin | _fpieee_flt | pow
atan, atan2 | _fpreset | printf, wprintf 1
_cabs | frexp | _scalb
ceil | _hypot | scanf, wscanf 1
_chgsign | _isnan | setjmp
_clear87, _clearfp | _j0 | sin
_control87, _controlfp | _j1 | sinh
_copysign | _jn | sqrt
cos | ldexp | _status87, _statusfp
cosh | log | tan
exp | log10 | tanh
fabs | _logb | _y0
_finite | longjmp | _y1
floor | _matherr | _yn
fmod | modf |

1 Although source code is available for most of this routine, it makes an internal call to another routine for which source code is not provided.

Some C run-time functions and C++ operators behave differently when called from a debug build of an application. (Note that a debug build of an application can be done by either defining the _DEBUG flag or by linking with a debug version of the C run-time library.) The behavioral differences usually consist of extra features or information provided by the routine to support the debugging process. The following table lists these routines.

Routines that Behave Differently in a Debug Build of an Application

C abort routine | C++ delete operator
C assert routine | C++ new operator

For more information about using the debug versions of the C++ operators in the preceding table, see Using the Debug Heap from C++.


Directory Control

These routines access, modify, and obtain information about the directory structure.

Directory-Control Routines

Routine | Use
_chdir, _wchdir | Change current working directory
_chdrive | Change current drive
_getcwd, _wgetcwd | Get current working directory for default drive
_getdcwd, _wgetdcwd | Get current working directory for specified drive
_getdrive | Get current (default) drive
_mkdir, _wmkdir | Make new directory
_rmdir, _wrmdir | Remove directory
_searchenv, _wsearchenv | Search for given file on specified paths


Error Handling

Use these routines to handle program errors.

Error-Handling Routines

Routine | Use
assert macro | Test for programming logic errors; available in both the release and debug versions of the run-time library
_ASSERT, _ASSERTE macros | Similar to assert, but only available in the debug versions of the run-time library
clearerr | Reset error indicator. Calling rewind or closing a stream also resets the error indicator.
_eof | Check for end of file in low-level I/O
feof | Test for end of file. End of file is also indicated when _read returns 0.
ferror | Test for stream I/O errors
_RPT, _RPTF macros | Generate a report similar to printf, but only available in the debug versions of the run-time library


Exception Handling Routines

Use the C++ exception-handling functions to recover from unexpected events during program execution.

Exception-Handling Functions

Function | Use
_set_se_translator | Handle Win32 exceptions (C structured exceptions) as C++ typed exceptions
set_terminate | Install your own termination routine to be called by terminate
set_unexpected | Install your own termination function to be called by unexpected
terminate | Called automatically under certain circumstances after exception is thrown. The terminate function calls abort or a function you specify using set_terminate
unexpected | Calls terminate or a function you specify using set_unexpected. The unexpected function is not used in current Microsoft C++ exception-handling implementation


File Handling

Use these routines to create, delete, and manipulate files and to set and check file-access permissions.

The C run-time libraries have a preset limit for the number of files that can be open at any one time. The limit for applications that link with the single-thread static library (LIBC.LIB) is 64 file handles or 20 file streams. Applications that link with either the static or dynamic multithread library (LIBCMT.LIB or MSVCRT.LIB and MSVCRT.DLL), have a limit of 256 file handles or 40 file streams. Attempting to open more than the maximum number of file handles or file streams causes program failure.

The following routines operate on files designated by a file handle:

File-Handling Routines (File Handle)

Routine | Use
_chsize | Change file size
_filelength | Get file length
_fstat, _fstati64 | Get file-status information on handle
_isatty | Check for character device
_locking | Lock areas of file
_setmode | Set file-translation mode

The following routines operate on files specified by a path or filename:

File-Handling Routines (Path or Filename)

Routine | Use
_access, _waccess | Check file-permission setting
_chmod, _wchmod | Change file-permission setting
_fullpath, _wfullpath | Expand a relative path to its absolute path name
_get_osfhandle | Return operating-system file handle associated with existing stream FILE pointer
_makepath, _wmakepath | Merge path components into single, full path
_mktemp, _wmktemp | Create unique filename
_open_osfhandle | Associate C run-time file handle with existing operating-system file handle
remove, _wremove | Delete file
rename, _wrename | Rename file
_splitpath, _wsplitpath | Parse path into components
_stat, _stati64, _wstat, _wstati64 | Get file-status information on named file
_umask | Set default permission mask for new files created by program
_unlink, _wunlink | Delete file


Floating-Point Support

Many Microsoft run-time library functions require floating-point support from a math coprocessor or from the floating-point libraries that accompany the compiler. Floating-point support functions are loaded only if required.

When you use a floating-point type specifier in the format string of a call to a function in the printf or scanf family, you must specify a floating-point value or a pointer to a floating-point value in the argument list to tell the compiler that floating-point support is required. The math functions in the Microsoft run-time library handle exceptions the same way that the UNIX V math functions do.

The Microsoft run-time library sets the default internal precision of the math coprocessor (or emulator) to 64 bits. This default applies only to the internal precision at which all intermediate calculations are performed; it does not apply to the size of arguments, return values, or variables. You can override this default and set the chip (or emulator) back to 80-bit precision by linking your program with LIB/FP10.OBJ. On the linker command line, FP10.OBJ must appear before LIBC.LIB, LIBCMT.LIB, or MSVCRT.LIB.

Floating-Point Functions

Routine | Use
abs | Return absolute value of int
acos | Calculate arccosine
asin | Calculate arcsine
atan, atan2 | Calculate arctangent
atof | Convert character string to double-precision floating-point value
Bessel functions | Calculate Bessel functions _j0, _j1, _jn, _y0, _y1, _yn
_cabs | Find absolute value of complex number
ceil | Find integer ceiling
_chgsign | Reverse sign of double-precision floating-point argument
_clear87, _clearfp | Get and clear floating-point status word
_control87, _controlfp | Get old floating-point control word and set new control-word value
_copysign | Return one value with sign of another
cos | Calculate cosine
cosh | Calculate hyperbolic cosine
difftime | Compute difference between two specified time values
div | Divide one integer by another, returning quotient and remainder
_ecvt | Convert double to character string of specified length
exp | Calculate exponential function
fabs | Find absolute value
_fcvt | Convert double to string with specified number of digits following decimal point
_finite | Determine whether given double-precision floating-point value is finite
floor | Find largest integer less than or equal to argument
fmod | Find floating-point remainder
_fpclass | Return status word containing information on floating-point class
_fpieee_flt | Invoke user-defined trap handler for IEEE floating-point exceptions
_fpreset | Reinitialize floating-point math package
frexp | Calculate exponential value
_gcvt | Convert floating-point value to character string
_hypot | Calculate hypotenuse of right triangle
_isnan | Check given double-precision floating-point value for not a number (NaN)
labs | Return absolute value of long
ldexp | Calculate product of argument and 2 to specified power
ldiv | Divide one long integer by another, returning quotient and remainder
log | Calculate natural logarithm
log10 | Calculate base-10 logarithm
_logb | Extract exponential value of double-precision floating-point argument
_lrotl, _lrotr | Shift unsigned long int left (_lrotl) or right (_lrotr)
_matherr | Handle math errors
__max | Return larger of two values
__min | Return smaller of two values
modf | Split argument into integer and fractional parts
_nextafter | Return next representable neighbor
pow | Calculate value raised to a power
printf, wprintf | Write data to stdout according to specified format
rand | Get pseudorandom number
_rotl, _rotr | Shift unsigned int left (_rotl) or right (_rotr)
_scalb | Scale argument by power of 2
scanf, wscanf | Read data from stdin according to specified format and write data to specified location
sin | Calculate sine
sinh | Calculate hyperbolic sine
sqrt | Find square root
srand | Initialize pseudorandom series
_status87, _statusfp | Get floating-point status word
strtod | Convert character string to double-precision value
tan | Calculate tangent
tanh | Calculate hyperbolic tangent


Long Double

Previous 16-bit versions of Microsoft C/C++ and Microsoft Visual C++ supported the long double, 80-bit precision data type. In Win32 programming, however, the long double data type maps to the double, 64-bit precision data type. The Microsoft run-time library provides long double versions of the math functions only for backward compatibility. The long double function prototypes are identical to the prototypes for their double counterparts, except that the long double data type replaces the double data type. The long double versions of these functions should not be used in new code.

Double Functions and Their Long Double Counterparts

Function | Long Double Counterpart | Function | Long Double Counterpart
acos | acosl | frexp | frexpl
asin | asinl | _hypot | _hypotl
atan | atanl | ldexp | ldexpl
atan2 | atan2l | log | logl
atof | _atold | log10 | log10l
Bessel functions j0, j1, jn | j0l, j1l, jnl | _matherr | _matherrl
Bessel functions y0, y1, yn | y0l, y1l, ynl | modf | modfl
_cabs | _cabsl | pow | powl
ceil | ceill | sin | sinl
cos | cosl | sinh | sinhl
cosh | coshl | sqrt | sqrtl
exp | expl | strtod | _strtold
fabs | fabsl | tan | tanl
floor | floorl | tanh | tanhl
fmod | fmodl |  |


Input and Output

The I/O functions read and write data to and from files and devices. File I/O operations take place in text mode or binary mode. The Microsoft run-time library has three types of I/O functions:

  • Stream I/O functions treat data as a stream of individual characters.

  • Low-level I/O functions invoke the operating system directly for lower-level operation than that provided by stream I/O.

  • Console and port I/O functions read or write directly to a console (keyboard and screen) or an I/O port (such as a printer port).

Warning Because stream functions are buffered and low-level functions are not, these two types of functions are generally incompatible. For processing a particular file, use either stream or low-level functions exclusively.


Text and Binary Mode File I/O

File I/O operations take place in one of two translation modes, text or binary, depending on the mode in which the file is opened. Data files are usually processed in text mode. To control the file translation mode, you can:

  • Retain the current default setting and specify the alternative mode only when you open selected files.

  • Change the default translation mode directly by setting the global variable _fmode in your program. The initial default setting of _fmode is _O_TEXT, for text mode.

When you call a file-open function such as _open, fopen, freopen, or _fsopen, you can override the current default setting of _fmode by specifying the appropriate argument to the function. The stdin, stdout, and stderr streams always open in text mode by default; you can also override this default when opening any of these files. Use _setmode to change the translation mode using the file handle after the file is open.


Unicode™ Stream I/O in Text and Binary Modes

When a Unicode stream I/O routine (such as fwprintf, fwscanf, fgetwc, fputwc, fgetws, or fputws) operates on a file that is open in text mode (the default), two kinds of character conversions take place:

  • Unicode-to-MBCS or MBCS-to-Unicode conversion. When a Unicode stream-I/O function operates in text mode, the source or destination stream is assumed to be a sequence of multibyte characters. Therefore, the Unicode stream-input functions convert multibyte characters to wide characters (as if by a call to the mbtowc function). For the same reason, the Unicode stream-output functions convert wide characters to multibyte characters (as if by a call to the wctomb function).

  • Carriage return – linefeed (CR-LF) translation. This translation occurs before the MBCS – Unicode conversion (for Unicode stream input functions) and after the Unicode – MBCS conversion (for Unicode stream output functions). During input, each carriage return – linefeed combination is translated into a single linefeed character. During output, each linefeed character is translated into a carriage return – linefeed combination.

However, when a Unicode stream-I/O function operates in binary mode, the file is assumed to be Unicode, and no CR-LF translation or character conversion occurs during input or output.


Stream I/O

These functions process data in different sizes and formats, from single characters to large data structures. They also provide buffering, which can improve performance. The default size of a stream buffer is 4K. These routines affect only buffers created by the run-time library routines, and have no effect on buffers created by the operating system.

Stream I/O Routines

Routine | Use
clearerr | Clear error indicator for stream
fclose | Close stream
_fcloseall | Close all open streams except stdin, stdout, and stderr
_fdopen, wfdopen | Associate stream with handle to open file
feof | Test for end of file on stream
ferror | Test for error on stream
fflush | Flush stream to buffer or storage device
fgetc, fgetwc | Read character from stream (function versions of getc and getwc)
_fgetchar, _fgetwchar | Read character from stdin (function versions of getchar and getwchar)
fgetpos | Get position indicator of stream
fgets, fgetws | Read string from stream
_fileno | Get file handle associated with stream
_flushall | Flush all streams to buffer or storage device
fopen, _wfopen | Open stream
fprintf, fwprintf | Write formatted data to stream
fputc, fputwc | Write a character to a stream (function versions of putc and putwc)
_fputchar, _fputwchar | Write character to stdout (function versions of putchar and putwchar)
fputs, fputws | Write string to stream
fread | Read unformatted data from stream
freopen, _wfreopen | Reassign FILE stream pointer to new file or device
fscanf, fwscanf | Read formatted data from stream
fseek | Move file position to given location
fsetpos | Set position indicator of stream
_fsopen, _wfsopen | Open stream with file sharing
ftell | Get current file position
fwrite | Write unformatted data items to stream
getc, getwc | Read character from stream (macro versions of fgetc and fgetwc)
getchar, getwchar | Read character from stdin (macro versions of fgetchar and fgetwchar)
gets, getws | Read line from stdin
_getw | Read binary int from stream
printf, wprintf | Write formatted data to stdout
putc, putwc | Write character to a stream (macro versions of fputc and fputwc)
putchar, putwchar | Write character to stdout (macro versions of fputchar and fputwchar)
puts, _putws | Write line to stream
_putw | Write binary int to stream
rewind | Move file position to beginning of stream
_rmtmp | Remove temporary files created by tmpfile
scanf, wscanf | Read formatted data from stdin
setbuf | Control stream buffering
_setmaxstdio | Set a maximum for the number of simultaneously open files at the stream I/O level.
setvbuf | Control stream buffering and buffer size
_snprintf, _snwprintf | Write formatted data of specified length to string
sprintf, swprintf | Write formatted data to string
sscanf, swscanf | Read formatted data from string
_tempnam, _wtempnam | Generate temporary filename in given directory
tmpfile | Create temporary file
tmpnam, _wtmpnam | Generate temporary filename
ungetc, ungetwc | Push character back onto stream
vfprintf, vfwprintf | Write formatted data to stream
vprintf, vwprintf | Write formatted data to stdout
_vsnprintf, _vsnwprintf | Write formatted data of specified length to buffer
vsprintf, vswprintf | Write formatted data to buffer

When a program begins execution, the startup code automatically opens several streams: standard input (pointed to by stdin), standard output (pointed to by stdout), and standard error (pointed to by stderr). These streams are directed to the console (keyboard and screen) by default. Use freopen to redirect stdin, stdout, or stderr to a disk file or a device.

Files opened using the stream routines are buffered by default. The stdout and stderr functions are flushed whenever they are full or, if you are writing to a character device, after each library call. If a program terminates abnormally, output buffers may not be flushed, resulting in loss of data. Use fflush or _flushall to ensure that the buffer associated with a specified file or all open buffers are flushed to the operating system, which can cache data before writing it to disk. The commit-to-disk feature ensures that the flushed buffer contents are not lost in the event of a system failure.

There are two ways to commit buffer contents to disk:

  • Link with the file COMMODE.OBJ to set a global commit flag. The default setting of the global flag is n, for “no-commit.”

  • Set the mode flag to c with fopen or _fdopen.

Any file specifically opened with either the c or the n flag behaves according to the flag, regardless of the state of the global commit/no-commit flag.

If your program does not explicitly close a stream, the stream is automatically closed when the program terminates. However, you should close a stream when your program finishes with it, as the number of streams that can be open at one time is limited. See _setmaxstdio for information on this limit.

Input can follow output directly only with an intervening call to fflush or to a file-positioning function (fseek, fsetpos, or rewind). Output can follow input without an intervening call to a file-positioning function if the input operation encounters the end of the file.


Low-level I/O

These functions invoke the operating system directly for lower-level operation than that provided by stream I/O. Low-level input and output calls do not buffer or format data.

Low-level routines can access the standard streams opened at program startup using the following predefined handles:

Stream | Handle
stdin | 0
stdout | 1
stderr | 2

Low-level I/O routines set the errno global variable when an error occurs. You must include STDIO.H when you use low-level functions only if your program requires a constant that is defined in STDIO.H, such as the end-of-file indicator (EOF).

Low-Level I/O Functions

Function | Use
_close | Close file
_commit | Flush file to disk
_creat, _wcreat | Create file
_dup | Return next available file handle for given file
_dup2 | Create second handle for given file
_eof | Test for end of file
_lseek, _lseeki64 | Reposition file pointer to given location
_open, _wopen | Open file
_read | Read data from file
_sopen, _wsopen | Open file for file sharing
_tell, _telli64 | Get current file-pointer position
_umask | Set file-permission mask
_write | Write data to file

_dup and _dup2 are typically used to associate the predefined file handles with different files.


Console and Port I/O

These routines read and write on your console or on the specified port. The console I/O routines are not compatible with stream I/O or low-level I/O library routines. The console or port does not have to be opened or closed before I/O is performed, so there are no open or close routines in this category. In Windows NT and Windows 95, the output from these functions is always directed to the console and cannot be redirected.

Console and Port I/O Routines

Routine | Use
_cgets | Read string from console
_cprintf | Write formatted data to console
_cputs | Write string to console
_cscanf | Read formatted data from console
_getch | Read character from console
_getche | Read character from console and echo it
_inp | Read one byte from specified I/O port
_inpd | Read double word from specified I/O port
_inpw | Read 2-byte word from specified I/O port
_kbhit | Check for keystroke at console; use before attempting to read from console
_outp | Write one byte to specified I/O port
_outpd | Write double word to specified I/O port
_outpw | Write word to specified I/O port
_putch | Write character to console
_ungetch | “Unget” last character read from console so it becomes next character read


Internationalization

The Microsoft run-time library provides many routines that are useful for creating different versions of a program for international markets. This includes locale-related routines, wide-character routines, multibyte-character routines, and generic-text routines. For convenience, most locale-related routines are also categorized in this reference according to the operations they perform. In this chapter and in this book’s alphabetic reference, multibyte-character routines and wide-character routines are described with single-byte-character counterparts, where they exist.


Locale

Use the setlocale function to change or query some or all of the current program locale information. “Locale” refers to the locality (the country and language) for which you can customize certain aspects of your program. Some locale-dependent categories include the formatting of dates and the display format for monetary values. For more information, see Locale Categories.

Locale-Dependent Routines

Routine | Use | setlocale Category Setting Dependence
atof, atoi, atol | Convert character to floating-point, integer, or long integer value, respectively | LC_NUMERIC
is Routines | Test given integer for particular condition. | LC_CTYPE
isleadbyte | Test for lead byte () | LC_CTYPE
localeconv | Read appropriate values for formatting numeric quantities | LC_MONETARY, LC_NUMERIC
MB_CUR_MAX | Maximum length in bytes of any multibyte character in current locale (macro defined in STDLIB.H) | LC_CTYPE
_mbccpy | Copy one multibyte character | LC_CTYPE
_mbclen | Return length, in bytes, of given multibyte character | LC_CTYPE
mblen | Validate and return number of bytes in multibyte character | LC_CTYPE
_mbstrlen | For multibyte-character strings: validate each character in string; return string length | LC_CTYPE
mbstowcs | Convert sequence of multibyte characters to corresponding sequence of wide characters | LC_CTYPE
mbtowc | Convert multibyte character to corresponding wide character | LC_CTYPE
printf functions | Write formatted output | LC_NUMERIC (determines radix character output)
scanf functions | Read formatted input | LC_NUMERIC (determines radix character recognition)
setlocale, _wsetlocale | Select locale for program | Not applicable
strcoll, wcscoll | Compare characters of two strings | LC_COLLATE
_stricoll, _wcsicoll | Compare characters of two strings (case insensitive) | LC_COLLATE
_strncoll, _wcsncoll | Compare first n characters of two strings | LC_COLLATE
_strnicoll, _wcsnicoll | Compare first n characters of two strings (case insensitive) | LC_COLLATE
strftime, wcsftime | Format date and time value according to supplied format argument | LC_TIME
_strlwr | Convert, in place, each uppercase letter in given string to lowercase | LC_CTYPE
strtod, wcstod, strtol, wcstol, strtoul, wcstoul | Convert character string to double, long, or unsigned long value | LC_NUMERIC (determines radix character recognition)
_strupr | Convert, in place, each lowercase letter in string to uppercase | LC_CTYPE
strxfrm, wcsxfrm | Transform string into collated form according to locale | LC_COLLATE
tolower, towlower | Convert given character to corresponding lowercase character | LC_CTYPE
toupper, towupper | Convert given character to corresponding uppercase letter | LC_CTYPE
wcstombs | Convert sequence of wide characters to corresponding sequence of multibyte characters | LC_CTYPE
wctomb | Convert wide character to corresponding multibyte character | LC_CTYPE
_wtoi, _wtol | Convert wide-character string to int or long | LC_NUMERIC


Code Pages

A code page is a character set, which can include numbers, punctuation marks, and other glyphs. Different languages and locales may use different code pages. For example, ANSI code page 1252 is used for American English and most European languages; OEM code page 932 is used for Japanese Kanji.

A code page can be represented in a table as a mapping of characters to single-byte values or multibyte values. Many code pages share the ASCII character set for characters in the range 0x00 – 0x7F.

The Microsoft run-time library uses the following types of code pages:

  • System-default ANSI code page. By default, at startup the run-time system automatically sets the multibyte code page to the system-default ANSI code page, which is obtained from the operating system. The call
    setlocale ( LC_ALL, "" );

    also sets the locale to the system-default ANSI code page.

  • Locale code page. The behavior of a number of run-time routines is dependent on the current locale setting, which includes the locale code page. (For more information, see Locale-Dependent Routines.) By default, all locale-dependent routines in the Microsoft run-time library use the code page that corresponds to the “C” locale. At run-time you can change or query the locale code page in use with a call to setlocale.

  • Multibyte code page. The behavior of most of the multibyte-character routines in the run-time library depends on the current multibyte code page setting. By default, these routines use the system-default ANSI code page. At run-time you can query and change the multibyte code page with _getmbcp and _setmbcp, respectively.

  • The “C” locale is defined by ANSI to correspond to the locale in which C programs have traditionally executed. The code page for the “C” locale (“C” code page) corresponds to the ASCII character set. For example, in the “C” locale, islower returns true for the values 0x61 – 0x7A only. In another locale, islower may return true for these as well as other values, as defined by that locale.


Interpretation of Multibyte-Character Sequences

Most multibyte-character routines in the Microsoft run-time library recognize multibyte-character sequences according to the current multibyte code page setting. The following multibyte-character routines depend instead on the locale code page (specifically, on the LC_CTYPE category setting of the current locale):

Locale-Dependent Multibyte Routines

Routine | Use
mblen | Validate and return number of bytes in multibyte character
_mbstrlen | For multibyte-character strings: validate each character in string; return string length
mbstowcs | Convert sequence of multibyte characters to corresponding sequence of wide characters
mbtowc | Convert multibyte character to corresponding wide character
wcstombs | Convert sequence of wide characters to corresponding sequence of multibyte characters
wctomb | Convert wide character to corresponding multibyte character


Single-byte and Multibyte Character Sets

The ASCII character set defines characters in the range 0x00 – 0x7F. There are a number of other character sets, primarily European, that define the characters within the range 0x00 – 0x7F identically to the ASCII character set and also define an extended character set from 0x80 – 0xFF. Thus an 8-bit, single-byte-character set (SBCS) is sufficient to represent the ASCII character set as well as the character sets for many European languages. However, some non-European character sets, such as Japanese Kanji, include many more characters than can be represented in a single-byte coding scheme, and therefore require multibyte-character set (MBCS) encoding.

Note Many SBCS routines in the Microsoft run-time library handle multibyte bytes, characters, and strings as appropriate. Many multibyte-character sets define the ASCII character set as a subset. In many multibyte character sets, each character in the range 0x00 – 0x7F is identical to the character that has the same value in the ASCII character set. For example, in both ASCII and MBCS character strings, the one-byte NULL character ('\0') has value 0x00 and indicates the terminating null character.

A multibyte character set may consist of both one-byte and two-byte characters. Thus a multibyte-character string may contain a mixture of single-byte and double-byte characters. A two-byte multibyte character has a lead byte and a trail byte. In a particular multibyte-character set, the lead bytes fall within a certain range, as do the trail bytes. When these ranges overlap, it may be necessary to evaluate the context to determine whether a given byte is functioning as a lead byte or a trail byte.


SBCS and MBCS Data Types

Any Microsoft MBCS run-time library routine that handles only one multibyte character or one byte of a multibyte character expects an unsigned int argument (where 0x00 <= character value <= 0xFFFF and 0x00 <= byte value <= 0xFF ). An MBCS routine that handles multibyte bytes or characters in a string context expects a multibyte-character string to be represented as an unsigned char pointer.

Caution Each byte of a multibyte character can be represented in an 8-bit char. However, an SBCS or MBCS single-byte character of type char with a value greater than 0x7F is negative. When such a character is converted directly to an int or a long, the result is sign-extended by the compiler and can therefore yield unexpected results.

Therefore it is best to represent a byte of a multibyte character as an 8-bit unsigned char. Or, to avoid a negative result, simply convert a single-byte character of type char to an unsigned char before converting it to an int or a long.

Because some SBCS string-handling functions take (signed) char* parameters, a type mismatch compiler warning will result when _MBCS is defined. There are three ways to avoid this warning, listed in order of efficiency:

  1. Use the “type-safe” inline function thunks in TCHAR.H. This is the default behavior.

  2. Use the “direct” macros in TCHAR.H by defining _MB_MAP_DIRECT on the command line. If you do this, you must manually match types. This is the fastest method, but is not type-safe.

  3. Use the “type-safe” statically linked library function thunks in TCHAR.H. To do so, define the constant _NO_INLINING on the command line. This is the slowest method, but the most type-safe.


Unicode: The Wide-Character Set

A wide character is a 2-byte multilingual character code. Any character in use in modern computing worldwide, including technical symbols and special publishing characters, can be represented according to the Unicode specification as a wide character. Developed and maintained by a large consortium that includes Microsoft, the Unicode standard is now widely accepted. Because every wide character is always represented in a fixed size of 16 bits, using wide characters simplifies programming with international character sets.

A wide character is of type wchar_t. A wide-character string is represented as a wchar_t[] array and is pointed to by a wchar_t* pointer. You can represent any ASCII character as a wide character by prefixing the letter L to the character. For example, L'\0' is the terminating wide (16-bit) NULL character. Similarly, you can represent any ASCII string literal as a wide-character string literal simply by prefixing the letter L to the ASCII literal (L"Hello").

Generally, wide characters take up more space in memory than multibyte characters but are faster to process. In addition, only one locale can be represented at a time in multibyte encoding, whereas all character sets in the world are represented simultaneously by the Unicode representation.


Using Generic-Text Mappings

Microsoft Specific —>

To simplify code development for various international markets, the Microsoft run-time library provides Microsoft-specific “generic-text” mappings for many data types, routines, and other objects. These mappings are defined in TCHAR.H. You can use these name mappings to write generic code that can be compiled for any of the three kinds of character sets: ASCII (SBCS), MBCS, or Unicode, depending on a manifest constant you define using a #define statement. Generic-text mappings are Microsoft extensions that are not ANSI compatible.

Preprocessor Directives for Generic-Text Mappings

#define | Compiled Version | Example
_UNICODE | Unicode (wide-character) | _tcsrev maps to _wcsrev
_MBCS | Multibyte-character | _tcsrev maps to _mbsrev
None (the default: neither _UNICODE nor _MBCS defined) | SBCS (ASCII) | _tcsrev maps to strrev

For example, the generic-text function _tcsrev, defined in TCHAR.H, maps to mbsrev if MBCS has been defined in your program, or to _wcsrev if _UNICODE has been defined. Otherwise _tcsrev maps to strrev.

The generic-text data type _TCHAR, also defined in TCHAR.H, maps to type char if _MBCS is defined, to type wchar_t if _UNICODE is defined, and to type char if neither constant is defined. Other data type mappings are provided in TCHAR.H for programming convenience, but _TCHAR is the type that is most useful.

Generic-Text Data Type Mappings

Generic-Text Data Type Name | SBCS (_UNICODE, _MBCS Not Defined) | _MBCS Defined | _UNICODE Defined
_TCHAR | char | char | wchar_t
_TINT | int | int | wint_t
_TSCHAR | signed char | signed char | wchar_t
_TUCHAR | unsigned char | unsigned char | wchar_t
_TXCHAR | char | unsigned char | wchar_t
_T or _TEXT | No effect (removed by preprocessor) | No effect (removed by preprocessor) | L (converts following character or string to its Unicode counterpart)

For a complete list of generic-text mappings of routines, variables, and other objects, see Appendix B, Generic-Text Mappings.

The following code fragments illustrate the use of _TCHAR and _tcsrev for mapping to the MBCS, Unicode, and SBCS models.

_TCHAR *RetVal, *szString;
RetVal = _tcsrev(szString);

If MBCS has been defined, the preprocessor maps the preceding fragment to the following code:

char *RetVal, *szString;
RetVal = _mbsrev(szString);

If _UNICODE has been defined, the preprocessor maps the same fragment to the following code:

wchar_t *RetVal, *szString;
RetVal = _wcsrev(szString);

If neither _MBCS nor _UNICODE has been defined, the preprocessor maps the fragment to single-byte ASCII code, as follows:

char *RetVal, *szString;
RetVal = strrev(szString);

Thus you can write, maintain, and compile a single source code file to run with routines that are specific to any of the three kinds of character sets.

See Also Generic-text mappings, Data type mappings, Constants and global variable mappings, Routine mappings, A sample generic-text propgram

END Microsoft Specific


A Sample Generic-Text Program

Microsoft Specific —>

The following program, GENTEXT.C, provides a more detailed illustration of the use of generic-text mappings defined in TCHAR.H:

/*
 * GENTEXT.C: use of generic-text mappings defined in TCHAR.H
 *            Generic-Text-Mapping example program
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <direct.h>
#include <errno.h>
#include <tchar.h>

int __cdecl _tmain(int argc, _TCHAR **argv, _TCHAR **envp)
{
   _TCHAR buff[_MAX_PATH];
   _TCHAR *str = _T("Astring");
   char *amsg = "Reversed";
   wchar_t *wmsg = L"Is";

#ifdef _UNICODE
   printf("Unicode version\n");
#else /* _UNICODE */
#ifdef _MBCS
   printf("MBCS version\n");
#else
   printf("SBCS version\n");
#endif
#endif /* _UNICODE */

   if (_tgetcwd(buff, _MAX_PATH) == NULL)
       printf("Can't Get Current Directory - errno=%d\n", errno);
   else
       _tprintf(_T("Current Directory is '%s'\n"), buff);
   _tprintf(_T("'%s' %hs %ls:\n"), str, amsg, wmsg);
   _tprintf(_T("'%s'\n"), _tcsrev(str));
   return 0;
}

If _MBCS has been defined, GENTEXT.C maps to the following MBCS program:

/*
 * MBCSGTXT.C: use of generic-text mappings defined in TCHAR.H
 *            Generic-Text-Mapping example program
 *            MBCS version of GENTEXT.C
 */

#include <stdlib.h>
#include <direct.h>

int __cdecl main(int argc, char **argv, char **envp)
{
   char buff[_MAX_PATH];
   char *str = "Astring";
   char *amsg = "Reversed";
   wchar_t *wmsg = L"Is";

   printf("MBCS version\n");

   if (_getcwd(buff, _MAX_PATH) == NULL) {
       printf("Can't Get Current Directory - errno=%d\n", errno);
   }
   else {
       printf("Current Directory is '%s'\n", buff);
   }

   printf("'%s' %hs %ls:\n", str, amsg, wmsg);
   printf("'%s'\n", _mbsrev(str));
   return 0;
}

If _UNICODE has been defined, GENTEXT.C maps to the following Unicode version of the program. For more information about using wmain in Unicode programs as a replacement for main, see Using wmain in C Language Reference.

/*
 * UNICGTXT.C: use of generic-text mappings defined in TCHAR.H
 *            Generic-Text-Mapping example program
 *            Unicode version of GENTEXT.C
 */

#include <stdlib.h>
#include <direct.h>

int __cdecl wmain(int argc, wchar_t **argv, wchar_t **envp)
{
   wchar_t buff[_MAX_PATH];
   wchar_t *str = L"Astring";
   char *amsg = "Reversed";
   wchar_t *wmsg = L"Is";

   printf("Unicode version\n");

   if (_wgetcwd(buff, _MAX_PATH) == NULL) {
      printf("Can't Get Current Directory - errno=%d\n", errno);
   }
   else {
       wprintf(L"Current Directory is '%s'\n", buff);
   }

   wprintf(L"'%s' %hs %ls:\n", str, amsg, wmsg);
   wprintf(L"'%s'\n", wcsrev(str));
   return 0;
}

If neither _MBCS nor _UNICODE has been defined, GENTEXT.C maps to single-byte ASCII code, as follows:

/*
 * SBCSGTXT.C: use of generic-text mappings defined in TCHAR.H
 *            Generic-Text-Mapping example program
 *            Single-byte (SBCS) Ascii version of GENTEXT.C
 */

#include <stdlib.h>
#include <direct.h>

int __cdecl main(int argc, char **argv, char **envp)
{
   char buff[_MAX_PATH];
   char *str = "Astring";
   char *amsg = "Reversed";
   wchar_t *wmsg = L"Is";

   printf("SBCS version\n");

   if (_getcwd(buff, _MAX_PATH) == NULL) {
       printf("Can't Get Current Directory - errno=%d\n", errno);
   }
   else {
       printf("Current Directory is '%s'\n", buff);
   }

   printf("'%s' %hs %ls:\n", str, amsg, wmsg);
   printf("'%s'\n", strrev(str));
   return 0;
}

See Also Generic-text mappings, Data type mappings, Constants and global variable mappings, Routine mappings, Using generic-text mappings

END Microsoft Specific


Using TCHAR.H Data Types with _MBCS

Microsoft Specific —>

As the table of generic-text routine mappings indicates (see Appendix B, Generic-Text Mappings), when the manifest constant _MBCS is defined, a given generic-text routine maps to one of the following kinds of routines:

  • An SBCS routine that handles multibyte bytes, characters, and strings appropriately. In this case, the string arguments are expected to be of type char*. For example, _tprintf maps to printf; the string arguments to printf are of type char*. If you use the _TCHAR generic-text data type for your string types, the formal and actual parameter types for printf match because _TCHAR* maps to char*.

  • An MBCS-specific routine. In this case, the string arguments are expected to be of type unsigned char*. For example, _tcsrev maps to _mbsrev, which expects and returns a string of type unsigned char*. Again, if you use the _TCHAR generic-text data type for your string types, there is a potential type conflict because _TCHAR maps to type char.

Following are three solutions for preventing this type conflict (and the C compiler warnings or C++ compiler errors that would result):

  • Use the default behavior. TCHAR.H provides generic-text routine prototypes for routines in the run-time libraries, as in the following example.
    char *_tcsrev(char *);

    In the default case, the prototype for _tcsrev maps to _mbsrev through a thunk in LIBC.LIB. This changes the types of the _mbsrev incoming parameters and outgoing return value from _TCHAR * (i.e., char *) to unsigned char *. This method ensures type matching when you are using _TCHAR, but it is relatively slow because of the function call overhead.

  • Use function inlining by incorporating the following preprocessor statement in your code.
    #define _USE_INLINING

    This method causes an inline function thunk, provided in TCHAR.H, to map the generic-text routine directly to the appropriate MBCS routine. The following code excerpt from TCHAR.H provides an example of how this is done.

    __inline char *_tcsrev(char *_s1)
{return (char *)_mbsrev((unsigned char *)_s1);}

    If you can use inlining, this is the best solution, because it guarantees type matching and has no additional time cost.

  • Use “direct mapping” by incorporating the following preprocessor statement in your code.
    #define _MB_MAP_DIRECT

    This approach provides a fast alternative if you do not want to use the default behavior or cannot use inlining. It causes the generic-text routine to be mapped by a macro directly to the MBCS version of the routine, as in the following example from TCHAR.H.

    #define _tcschr _mbschr

When you take this approach, you must be careful to ensure that appropriate data types are used for string arguments and string return values. You can use type casting to ensure proper type matching or you can use the _TXCHAR generic-text data type. _TXCHAR maps to type char in SBCS code but maps to type unsigned char in MBCS code. For more information about generic-text macros, see Appendix B, Generic-Text Mappings.

END Microsoft Specific


Memory Allocation

Use these routines to allocate, free, and reallocate memory.

Memory-Allocation Routines

Routine | Use
_alloca | Allocate memory from stack
calloc | Allocate storage for array, initializing every byte in allocated block to 0
_calloc_dbg | Debug version of calloc; only available in the debug versions of the run-time libraries
_expand | Expand or shrink block of memory without moving it
_expand_dbg | Debug version of _expand; only available in the debug versions of the run-time libraries
free | Free allocated block
_free_dbg | Debug version of free; only available in the debug versions of the run-time libraries
_get_sbh_threshold | Return the upper limit for the size of a memory allocation that will be supported by the small-block heap
_heapadd | Add memory to heap
_heapchk | Check heap for consistency
_heapmin | Release unused memory in heap
_heapset | Fill free heap entries with specified value
_heapwalk | Return information about each entry in heap
malloc | Allocate block of memory from heap
_malloc_dbg | Debug version of malloc; only available in the debug versions of the run-time libraries
_msize | Return size of allocated block
_msize_dbg | Debug version of _msize; only available in the debug versions of the run-time libraries
_query_new_handler | Return address of current new handler routine as set by _set_new_handler
_query_new_mode | Return integer indicating new handler mode set by _set_new_mode for malloc
realloc | Reallocate block to new size
_realloc_dbg | Debug version of realloc; only available in the debug versions of the run-time libraries
_set_new_handler | Enable error-handling mechanism when new operator fails (to allocate memory) and enable compilation of Standard Template Libraries (STL)
_set_new_mode | Set new handler mode for malloc
_set_sbh_threshold | Set the upper limit for the size of a memory allocation that will be supported by the small-block heap


Process and Environment Control

Use the process-control routines to start, stop, and manage processes from within a program. Use the environment-control routines to get and change information about the operating-system environment.

Process and Environment Control Functions

Routine | Use
abort | Abort process without flushing buffers or calling functions registered by atexit and _onexit
assert | Test for logic error
_ASSERT, _ASSERTE macros | Similar to assert, but only available in the debug versions of the run-time libraries
atexit | Schedule routines for execution at program termination
_beginthread, _beginthreadex | Create a new thread on a Windows NT or Windows 95 process
_cexit | Perform exit termination procedures (such as flushing buffers), then return control to calling program without terminating process
_c_exit | Perform _exit termination procedures, then return control to calling program without terminating process
_cwait | Wait until another process terminates
_endthread, _endthreadex | Terminate a Windows NT or Windows 95 thread
_execl, _wexecl | Execute new process with argument list
_execle, _wexecle | Execute new process with argument list and given environment
_execlp, _wexeclp | Execute new process using PATH variable and argument list
_execlpe, _wexeclpe | Execute new process using PATH variable, given environment, and argument list
_execv, _wexecv | Execute new process with argument array
_execve, _wexecve | Execute new process with argument array and given environment
_execvp, _wexecvp | Execute new process using PATH variable and argument array
_execvpe, _wexecvpe | Execute new process using PATH variable, given environment, and argument array
exit | Call functions registered by atexit and _onexit, flush all buffers, close all open files, and terminate process
_exit | Terminate process immediately without calling atexit or _onexit or flushing buffers
getenv, _wgetenv | Get value of environment variable
_getpid | Get process ID number
longjmp | Restore saved stack environment; use it to execute a nonlocal goto
_onexit | Schedule routines for execution at program termination; use for compatibility with Microsoft C/C++ version 7.0 and earlier
_pclose | Wait for new command processor and close stream on associated pipe
perror, _wperror | Print error message
_pipe | Create pipe for reading and writing
_popen, _wpopen | Create pipe and execute command
_putenv, _wputenv | Add or change value of environment variable
raise | Send signal to calling process
setjmp | Save stack environment; use to execute nonlocal goto
signal | Handle interrupt signal
_spawnl, _wspawnl | Create and execute new process with specified argument list
_spawnle, _wspawnle | Create and execute new process with specified argument list and environment
_spawnlp, _wspawnlp | Create and execute new process using PATH variable and specified argument list
_spawnlpe, _wspawnlpe | Create and execute new process using PATH variable, specified environment, and argument list
_spawnv, _wspawnv | Create and execute new process with specified argument array
_spawnve, _wspawnve | Create and execute new process with specified environment and argument array
_spawnvp, _wspawnvp | Create and execute new process using PATH variable and specified argument array
_spawnvpe, _wspawnvpe | Create and execute new process using PATH variable, specified environment, and argument array
system, _wsystem | Execute operating-system command

In Windows NT and Windows 95, the spawned process is equivalent to the spawning process. Therefore, the OS/2® wait function, which allows a parent process to wait for its children to terminate, is not available. Instead, any process can use _cwait to wait for any other process for which the process ID is known.

The difference between the _exec and _spawn families is that a _spawn function can return control from the new process to the calling process. In a _spawn function, both the calling process and the new process are present in memory unless _P_OVERLAY is specified. In an _exec function, the new process overlays the calling process, so control cannot return to the calling process unless an error occurs in the attempt to start execution of the new process.

The differences among the functions in the _exec family, as well as among those in the _spawn family, involve the method of locating the file to be executed as the new process, the form in which arguments are passed to the new process, and the method of setting the environment, as shown in the following table. Use a function that passes an argument list when the number of arguments is constant or is known at compile time. Use a function that passes a pointer to an array containing the arguments when the number of arguments is to be determined at run time. The information in the following table also applies to the wide-character counterparts of the _spawn and _exec functions.

_spawn and _exec Function Families

Functions | Use PATH Variable to Locate File | Argument- Passing Convention | Environment Settings
_execl, _spawnl | No | List | Inherited from calling process
_execle, _spawnle | No | List | Pointer to environment table for new process passed as last argument
_execlp, _spawnlp | Yes | List | Inherited from calling process
_execlpe, _spawnlpe | Yes | List | Pointer to environment table for new process passed as last argument
_execv, _spawnv | No | Array | Inherited from calling process
_execve, _spawnve | No | Array | Pointer to environment table for new process passed as last argument
_execvp, _spawnvp | Yes | Array | Inherited from calling process
_execvpe, _spawnvpe | Yes | Array | Pointer to environment table for new process passed as last argument


Searching and Sorting

Use the following functions for searching and sorting:

Searching and Sorting Functions

Function | Search or Sort
bsearch | Binary search
_lfind | Linear search for given value
_lsearch | Linear search for given value, which is added to array if not found
qsort | Quick sort


String Manipulation

These routines operate on null-terminated single-byte character, wide-character, and multibyte-character strings. Use the buffer-manipulation routines, described in Buffer Manipulation, to work with character arrays that do not end with a null character.

String-Manipulation Routines

Routine | Use
_mbscoll, _mbsicoll, _mbsncoll, _mbsnicoll | Compare two multibyte-character strings using multibyte code page information (_mbsicoll and _mbsnicoll are case-insensitive)
_mbsdec, _strdec, _wcsdec | Move string pointer back one character
_mbsinc, _strinc, _wcsinc | Advance string pointer by one character
_mbslen | Get number of multibyte characters in multibyte-character string; dependent upon OEM code page
_mbsnbcat | Append, at most, first n bytes of one multibyte-character string to another
_mbsnbcmp | Compare first n bytes of two multibyte-character strings
_mbsnbcnt | Return number of multibyte-character bytes within supplied character count
_mbsnbcpy | Copy n bytes of string
_mbsnbicmp | Compare n bytes of two multibyte-character strings, ignoring case
_mbsnbset | Set first n bytes of multibyte-character string to specified character
_mbsnccnt | Return number of multibyte characters within supplied byte count
_mbsnextc, _strnextc, _wcsnextc | Find next character in string
_mbsninc. _strninc, _wcsninc | Advance string pointer by n characters
_mbsspnp, _strspnp, _wcsspnp | Return pointer to first character in given string that is not in another given string
_mbstrlen | Get number of multibyte characters in multibyte-character string; locale-dependent
sprintf, _stprintf | Write formatted data to a string
strcat, wcscat, _mbscat | Append one string to another
strchr, wcschr, _mbschr | Find first occurrence of specified character in string
strcmp, wcscmp, _mbscmp | Compare two strings
strcoll, wcscoll, _stricoll, _wcsicoll, _strncoll, _wcsncoll, _strnicoll, _wcsnicoll | Compare two strings using current locale code page information (_stricoll, _wcsicoll, _strnicoll, and _wcsnicoll are case-insensitive)
strcpy, wcscpy, _mbscpy | Copy one string to another
strcspn, wcscspn, _mbscspn, | Find first occurrence of character from specified character set in string
_strdup, _wcsdup, _mbsdup | Duplicate string
strerror | Map error number to message string
_strerror | Map user-defined error message to string
strftime, wcsftime | Format date-and-time string
_stricmp, _wcsicmp, _mbsicmp | Compare two strings without regard to case
strlen, wcslen, _mbslen, _mbstrlen | Find length of string
_strlwr, _wcslwr, _mbslwr | Convert string to lowercase
strncat, wcsncat, _mbsncat | Append characters of string
strncmp, wcsncmp, _mbsncmp | Compare characters of two strings
strncpy, wcsncpy, _mbsncpy | Copy characters of one string to another
_strnicmp, _wcsnicmp, _mbsnicmp | Compare characters of two strings without regard to case
_strnset, _wcsnset, _mbsnset | Set first n characters of string to specified character
strpbrk, wcspbrk, _mbspbrk | Find first occurrence of character from one string in another string
strrchr, wcsrchr,_mbsrchr | Find last occurrence of given character in string
_strrev, _wcsrev,_mbsrev | Reverse string
_strset, _wcsset, _mbsset | Set all characters of string to specified character
strspn, wcsspn, _mbsspn | Find first substring from one string in another string
strstr, wcsstr, _mbsstr | Find first occurrence of specified string in another string
strtok, wcstok, _mbstok | Find next token in string
_strupr, _wcsupr, _mbsupr | Convert string to uppercase
strxfrm, wcsxfrm | Transform string into collated form based on locale-specific information
vsprintf, _vstprint | Write formatted output using a pointer to a list of arguments


System Calls

The following functions are Windows NT and Windows 95 operating-system calls:

System Call Functions

Function | Use
_findclose | Release resources from previous find operations
_findfirst, _findfirsti64, _wfindfirst, _wfindfirsti64 | Find file with specified attributes
_findnext, _findnexti64, _wfindnext, _wfindnexti64 | Find next file with specified attributes


Time Management

Use these functions to get the current time and convert, adjust, and store it as necessary. The current time is the system time.

The _ftime and localtime routines use the TZ environment variable. If TZ is not set, the run-time library attempts to use the time-zone information specified by the operating system. If this information is unavailable, these functions use the default value of PST8PDT. For more information on TZ, see _tzset; also see _daylight, timezone, and _tzname.

Time Routines

Function | Use
asctime, _wasctime | Convert time from type struct tm to character string
clock | Return elapsed CPU time for process
ctime, _wctime | Convert time from type time_t to character string
difftime | Compute difference between two times
_ftime | Store current system time in variable of type struct _timeb
_futime | Set modification time on open file
gmtime | Convert time from type time_t to struct tm
localtime | Convert time from type time_t to struct tm with local correction
mktime | Convert time to calendar value
_strdate, _wstrdate | Return current system date as string
strftime, wcsftime | Format date-and-time string for international use
_strtime, _wstrtime | Return current system time as string
time | Get current system time as type time_t
_tzset | Set external time variables from environment time variable TZ
_utime, _wutime | Set modification time for specified file using either current time or time value stored in structure

Note In all versions of Microsoft C/C++ except Microsoft C/C++ version 7.0, and in all versions of Microsoft Visual C++, the time function returns the current time as the number of seconds elapsed since midnight on January 1, 1970. In Microsoft C/C++ version 7.0, time returned the current time as the number of seconds elapsed since midnight on December 31, 1899.


Global Variables and Standard Types

The Microsoft run-time library contains definitions for global variables, control flags, and standard types used by library routines. Access these variables, flags, and types by declaring them in your program or by including the appropriate header files.


Global Variables

The Microsoft run-time library provides the following global variables.

Variable | Description
_amblksiz | Controls memory heap granularity
daylight, _timezone, _tzname | Adjust for local time; used in some date and time functions
_doserrno, errno, _sys_errlist, _sys_nerr | Store error codes and related information
_environ, _wenviron | Pointers to arrays of pointers to strings that constitute process environment
_fileinfo | Specifies whether information regarding open files of a process is passed to new processes
_fmode | Sets default file-translation mode
_osver, _winmajor, _winminor, _winver | Store build and version numbers of operating system
_pgmptr, _wpgmptr | Initialized at program startup to value such as program name, filename, relative path, or full path


_amblksiz

_amblksiz controls memory heap granularity. It is declared in MALLOC.H as

extern unsigned int _amblksiz;

The value of _amblksiz specifies the size of blocks allocated by the operating system for the heap. The initial requested size for a segment of heap memory is just enough to satisfy the current allocation request (for example, a call to malloc) plus memory required for heap manager overhead. The value of _amblksiz should represent a trade-off between the number of times the operating system is to be called to increase the heap to required size and the amount of memory potentially wasted (available but not used) at the end of the heap.

The default value of _amblksiz is 8K. You can change this value by direct assignment in your program. For example:

_amblksiz = 2045;

If you assign a value to _amblksiz, the actual value used internally by the heap manager is the assigned value rounded up to the nearest whole power of 2. Thus, in the previous example, the heap manager would reset the value of _amblksize to 2048.


_daylight, _timezone, and _tzname

_daylight, _timezone, and _tzname are used in some time and date routines to make local-time adjustments. They are declared in TIME.H as

extern int _daylight;

extern long _timezone;

extern char *_tzname[2];

On a call to _ftime, localtime, or _tzset, the values of _daylight, _timezone, and _tzname are determined from the value of the TZ environment variable. If you do not explicitly set the value of TZ, _tzname[0] and _tzname[1] contain empty strings, but the time-manipulation functions (_tzset, _ftime, and localtime) attempt to set the values of _daylight and _timezone by querying the operating system for the default value of each variable. The time-zone global variable values are as follows.

Variable | Value
_daylight | Nonzero if daylight-saving-time zone (DST) is specified in TZ; otherwise, 0. Default value is 1.
_timezone | Difference in seconds between coordinated universal time and local time. Default value is 28,800.
_tzname[0] | Time-zone name derived from TZ environment variable.
_tzname[1] | DST zone name derived from TZ environment variable. Default value is PDT (Pacific daylight time). If DST zone is omitted from TZ, _tzname[1] is empty string.


_doserrno, errno, _sys_errlist, and _sys_nerr

These global variables hold error codes used by the perror and strerror functions for printing error messages. Manifest constants for these variables are declared in STDLIB.H as follows:

extern int _doserrno;

extern int errno;

extern char *_sys_errlist[ ];

extern int _sys_nerr;

errno is set on an error in a system-level call. Because errno holds the value for the last call that set it, this value may be changed by succeeding calls. Always check errno immediately before and after a call that may set it. All errno values, defined as manifest constants in ERRNO.H, are UNIX-compatible. The values valid for 32-bit Windows applications are a subset of these UNIX values.

On an error, errno is not necessarily set to the same value as the error code returned by a system call. For I/O operations only, use _doserrno to access the operating-system error-code equivalents of errno codes. For other operations the value of _doserrno is undefined.

Each errno value is associated with an error message that can be printed using perror or stored in a string using strerror. perror and strerror use the _sys_errlist array and _sys_nerr, the number of elements in _sys_errlist, to process error information.

Library math routines set errno by calling _matherr. To handle math errors differently, write your own routine according to the _matherr reference description and name it _matherr.

The following errno values are compatible with 32-bit Windows applications. Only ERANGE and EDOM are specified in the ANSI standard.

Constant | System Error Message | Value
E2BIG | Argument list too long | 7
EACCES | Permission denied | 13
EAGAIN | No more processes or not enough memory or maximum nesting level reached | 11
EBADF | Bad file number | 9
ECHILD | No spawned processes | 10
EDEADLOCK | Resource deadlock would occur | 36
EDOM | Math argument | 33
EEXIST | File exists | 17
EINVAL | Invalid argument | 22
EMFILE | Too many open files | 24
ENOENT | No such file or directory | 2
ENOEXEC | Exec format error | 8
ENOMEM | Not enough memory | 12
ENOSPC | No space left on device | 28
ERANGE | Result too large | 34
EXDEV | Cross-device link | 18


_environ, _wenviron

The _environ variable is a pointer to an array of pointers to the multibyte-character strings that constitute the process environment. _environ is declared in STDLIB.H as

extern char **_environ;

In a program that uses the main function, _environ is initialized at program startup according to settings taken from the operating-system environment. The environment consists of one or more entries of the form

ENVVARNAME=string

getenv and _putenv use the _environ variable to access and modify the environment table. When _putenv is called to add or delete environment settings, the environment table changes size. Its location in memory may also change, depending on the program’s memory requirements. The value of _environ is automatically adjusted accordingly.

The _wenviron variable, declared in STDLIB.H as extern wchar_t **_wenviron;, is a wide-character version of _environ. In a program that uses the wmain function, _wenviron is initialized at program startup according to settings taken from the operating-system environment.

In a program that uses main, _wenviron is initially NULL, because the environment is composed of multibyte-character strings. On the first call to _wgetenv or _wputenv, a corresponding wide-character string environment is created and is pointed to by _wenviron.

Similarly, in a program that uses wmain, _environ is initially NULL because the environment is composed of wide-character strings. On the first call to _getenv or _putenv, a corresponding wide-character string environment is created and is pointed to by _environ.

When two copies of the environment (MBCS and Unicode) exist simultaneously in a program, the run-time system must maintain both copies, resulting in slower execution time. For example, whenever you call _putenv, a call to _wputenv is also executed automatically, so that the two environment strings correspond.

Caution In rare instances, when the run-time system is maintaining both a Unicode version and a multibyte version of the environment, these two environment versions may not correspond exactly. This is because, although any unique multibyte-character string maps to a unique Unicode string, the mapping from a unique Unicode string to a multibyte-character string is not necessarily unique. Therefore, two distinct Unicode strings may map to the same multibyte string.

The following pseudocode illustrates how this can happen.

int i, j;
i = _wputenv( "env_var_x=string1" );  // results in the implicit call:
                                      // putenv ("env_var_z=string1")
j = _wputenv( "env_var_y=string2" );  // also results in implicit call:
                                      // putenv("env_var_z=string2")

In the notation used for this example, the character strings are not C string literals; rather, they are placeholders that represent Unicode environment string literals in the _wputenv call and multibyte environment strings in the putenv call. The character-placeholders 'x' and 'y' in the two distinct Unicode environment strings do not map uniquely to characters in the current MBCS. Instead, both map to some MBCS character 'z' that is the default result of the attempt to convert the strings.

Thus in the multibyte environment the value of "env_var_z" after the first implicit call to putenv would be "string1", but this value would be overwritten on the second implicit call to putenv, when the value of "env_var_z" is set to "string2". The Unicode environment (in _wenviron) and the multibyte environment (in _environ) would therefore differ following this series of calls.


_fileinfo

The _fileinfo variable determines whether information about the open files of a process is passed to new processes by functions such as _spawn. _fileinfo is declared in STDLIB.H as

extern int _fileinfo;

If _fileinfo is 0 (the default), information about open files is not passed to new processes; otherwise the information is passed. You can modify the default value of _fileinfo by setting the _fileinfo variable to a nonzero value in your program.


_fmode

The _fmode variable sets the default file-translation mode for text or binary translation. It is declared in STDLIB.H as

extern int _fmode;

The default setting of _fmode is _O_TEXT for text-mode translation. _O_BINARY is the setting for binary mode.

You can change the value of _fmode in either of two ways:

  • Link with BINMODE.OBJ. This changes the initial setting of _fmode to _O_BINARY, causing all files except stdin, stdout, and stderr to be opened in binary mode.

  • Change the value of _fmode directly by setting it in your program.


_osver, _winmajor, _winminor, _winver

These variables store build and version numbers of the 32-bit Windows operating systems. Declarations for these variables in STDLIB.H are as follows:

extern unsigned int _osver;

extern unsigned int _winmajor;

extern unsigned int _winminor;

extern unsigned int _winver;

These variables are useful in programs that run in different versions of Windows NT or Windows 95.

Variable | Description
_osver | Current build number
_winmajor | Major version number
_winminor | Minor version number
_winver | Holds value of _winmajor in high byte and value of _winminor in low byte


_pgmptr, _wpgmptr

When a program is run from the command interpreter (CMD.EXE), _pgmptr is automatically initialized to the full path of the executable file. For example, if HELLO.EXE is in C:\BIN and C:\BIN is in the path, _pgmptr is set to C:\BIN\HELLO.EXE when you execute

C> hello

When a program is not run from the command line, _pgmptr may be initialized to the program name (the file’s base name without the extension), or to a filename, a relative path, or a full path.

_wpgmptr is the wide-character counterpart of _pgmptr for use with programs that use wmain. _pgmptr and _wpgmptr are declared in STDLIB.H as

extern char *_pgmptr;

extern wchar_t *_pgmptr;

The following program demonstrates the use of _pgmptr.

/*
 * PGMPTR.C: The following program demonstrates the use of _pgmptr.
 */

#include <stdio.h>
#include <stdlib.h>
void main( void )
{
   printf("The full path of the executing program is : %Fs\n",
     _pgmptr);
}


Control Flags

The debug version of the Microsoft C run-time library uses the following flags to control the heap allocation and reporting process. For more information, see Using C Run-Time Library Debugging Support.

Flag | Description
_CRTDBG_MAP_ALLOC | Maps the base heap functions to their debug version counterparts
_DEBUG | Enables the use of the debugging versions of the run-time functions
_crtDbgFlag | Controls how the debug heap manager tracks allocations

These flags can be defined with a /D command-line option or with a #define directive. When the flag is defined with #define, the directive must appear before the header file include statement for the routine declarations.


_CRTDBG_MAP_ALLOC

When the _CRTDBG_MAP_ALLOC flag is defined in the debug version of an application, the base version of the heap functions are directly mapped to their debug versions. This flag is declared in CRTDBG.H. This flag is only available when the _DEBUG flag has been defined in the application.

For more information about using the debug version versus the base version of a heap function, see Using the Debug Version Versus the Base Version.


_DEBUG

The compiler defines _DEBUG when you specify the /MTd or /Mdd option. These options specify debug versions of the C runtime library.

For more information, see Using C Run-Time Library Debugging Support.


_crtDbgFlag

The _crtDbgFlag flag consists of five bit fields that control how memory allocations on the debug version of the heap are tracked, verified, reported, and dumped. The bit fields of the flag are set using the _CrtSetDbgFlag function. This flag and its bit fields are declared in CRTDBG.H. This flag is only available when the _DEBUG flag has been defined in the application.

For more information about using this flag in conjunction with other debug functions, see Heap State Reporting Functions.


Standard Types

The Microsoft run-time library defines the following standard types.

Type | Description | Declared In
clock_t structure | Stores time values; used by clock. | TIME.H
_complex structure | Stores real and imaginary parts of complex numbers; used by _cabs. | MATH.H
_dev_t short or unsigned integer | Represents device handles. | SYS\TYPES.H
div_t, ldiv_t structures | Store values returned by div and ldiv, respectively. | STDLIB.H
_exception structure | Stores error information for _matherr. | MATH.H
FILE structure | Stores information about current state of stream; used in all stream I/O operations. | STDIO.H
_finddata_t, _wfinddata_t, _wfinddatai64_t structures | _finddata_t stores file-attribute information returned by _findfirst and _findnext. _wfinddata_t stores file-attribute information returned by _wfindfirst and _wfindnext. _wfinddatai64_t stores file-attribute information returned by _wfindfirsti64 and _wfindnexti64. | _finddata_t: IO.H _wfinddata_t: IO.H, WCHAR.H _wfinddatai64_t: IO.H, WCHAR.H
_FPIEEE_RECORD structure | Contains information pertaining to IEEE floating-point exception; passed to user-defined trap handler by _fpieee_flt. | FPIEEE.H
fpos_t (long integer, __int64, or structure, depending on the target platform) | Used by fgetpos and fsetpos to record information for uniquely specifying every position within a file. | STDIO.H
_HEAPINFO structure | Contains information about next heap entry for _heapwalk. | MALLOC.H
jmp_buf array | Used by setjmp and longjmp to save and restore program environment. | SETJMP.H
lconv structure | Contains formatting rules for numeric values in different countries. | LOCALE.H
_off_t long integer | Represents file-offset value. | SYS\TYPES.H
_onexit_t pointer | Returned by _onexit. | STDLIB.H
_PNH pointer to function | Type of argument to _set_new_handler. | NEW.H
ptrdiff_t integer | Result of subtraction of two pointers. | STDDEF.H
sig_atomic_t integer | Type of object that can be modified as atomic entity, even in presence of asynchronous interrupts; used with signal. | SIGNAL.H
size_t unsigned integer | Result of sizeof operator. | STDDEF.H and other include files
_stat structure | Contains file-status information returned by _stat and _fstat. | SYS\STAT.H
time_t long integer | Represents time values in mktime and time. | TIME.H
_timeb structure | Used by _ftime to store current system time. | SYS\TIMEB.H
tm structure | Used by asctime, gmtime, localtime, mktime, and strftime to store and retrieve time information. | TIME.H
_utimbuf structure | Stores file access and modification times used by _utime to change file-modification dates. | SYS\UTIME.H
va_list structure | Used to hold information needed by va_arg and va_end macros. Called function declares variable of type va_list that can be passed as argument to another function. | STDARG.H
wchar_t internal type of a wide character | Useful for writing portable programs for international markets. | STDDEF.H, STDLIB.H
wctrans_t integer | Represents locale-specific character mappings. | WCTYPE.H
wctype_t integer | Can represent all characters of any national character set. | WCHAR.H
wint_t integer | Type of data object that can hold any wide character or wide end-of-file value. | WCHAR.H


Global Constants

The Microsoft run-time library contains definitions for global constants used by library routines. To use these constants, include the appropriate header files as indicated in the description for each constant. The global constants are listed in the following table.

BUFSIZ | __LOCAL_SIZE
CLOCKS_PER_SEC, CLK_TCK | Locale Categories
Commit-To-Disk Constants | _locking Constants
Data Type Constants | Math Error Constants
EOF, WEOF | MB_CUR_MAX
errno | NULL
Exception-Handling Constants | Path Field Limits
EXIT_SUCCESS, EXIT_FAILURE | RAND_MAX
File Attribute Constants | setvbuf Constants
File Constants | Sharing Constants
File Permission Constants | signal Constants
File Read/Write Access Constants | signal Action Constants
File Translation Constants | _spawn Constants
FILENAME_MAX | _stat Structure st_mode Field Constants
FOPEN_MAX, _SYS_OPEN | stdin, stdout, stderr
_FREEENTRY, _USEDENTRY | TMP_MAX, L_tmpnam
fseek, _lseek | Translation Mode Constants
Heap Constants | _WAIT_CHILD, _WAIT_GRANDCHILD
_HEAP_MAXREQ | 32-bit Windows Time/Date Formats
HUGE_VAL |


BUFSIZ

#include <stdio.h>

Remarks

BUFSIZ is the required user-allocated buffer for the setvbuf routine.

Stream I/O


CLOCKS_PER_SEC, CLK_TCK

#include <time.h>

Remarks

The time in seconds is the value returned by the clock function, divided by CLOCKS_PER_SEC. CLK_TCK is equivalent, but considered obsolete.

See Also clock


Commit-To-Disk Constants

Microsoft Specific —>

#include <stdio.h>

Remarks

These Microsoft-specific constants specify whether the buffer associated with the open file is flushed to operating system buffers or to disk. The mode is included in the string specifying the type of read/write access ("r", "w", "a", "r+", "w+", "a+").

The commit-to-disk modes are as follows:

c

Writes the unwritten contents of the specified buffer to disk. This commit-to-disk functionality only occurs at explicit calls to either the fflush or the _flushall function. This mode is useful when dealing with sensitive data. For example, if your program terminates after a call to fflush or _flushall, you can be sure that your data reached the operating system's buffers. However, unless a file is opened with the c option, the data might never make it to disk if the operating system also terminates.

n

Writes the unwritten contents of the specified buffer to the operating system's buffers. The operating system can cache data and then determine an optimal time to write to disk. Under many conditions, this behavior makes for efficient program behavior. However, if the retention of data is critical (such as bank transactions or airline ticket information) consider using the c option. The n mode is the default.

Note The c and n options are not part of the ANSI standard for fopen, but are Microsoft extensions and should not be used where ANSI portability is desired.

Using the Commit-to-Disk Feature with Existing Code

By default, calls to the fflush or _flushall library functions write data to buffers maintained by the operating system. The operating system determines the optimal time to actually write the data to disk. The commit-to-disk feature of the run-time library lets you ensure that critical data is written directly to disk rather than to the operating system's buffers. You can give this capability to an existing program without rewriting it by linking its object files with COMMODE.OBJ.

In the resulting executable file, calls to fflush write the contents of the buffer directly to disk, and calls to _flushall write the contents of all buffers to disk. These two functions are the only ones affected by COMMODE.OBJ.

END Microsoft Specific

Stream I/O

See Also _fdopen, fopen


Data Type Constants

Remarks

Data type constants are implementation-dependent ranges of values allowed for integral data types. The constants listed below give the ranges for the integral data types and are defined in LIMITS.H.

Note The /J compiler option changes the default char type to unsigned.

Constant | Value | Meaning
SCHAR_MAX | 127 | Maximum signed char value
SCHAR_MIN | –128 | Minimum signed char value
UCHAR_MAX | 255 (0xff) | Maximum unsigned char value
CHAR_BIT | 8 | Number of bits in a char
USHRT_MAX | 65535 (0xffff) | Maximum unsigned short value
SHRT_MAX | 32767 | Maximum (signed) short value
SHRT_MIN | –32768 | Minimum (signed) short value
UINT_MAX | 4294967295 (0xffffffff) | Maximum unsigned int value
ULONG_MAX | 4294967295 (0xffffffff) | Maximum unsigned long value
INT_MAX | 2147483647 | Maximum (signed) int value
INT_MIN | –2147483647–1 | Minimum (signed) int value
LONG_MAX | 2147483647 | Maximum (signed) long value
LONG_MIN | –2147483647–1 | Minimum (signed) long value
CHAR_MAX | 127 (255 if /J option used) | Maximum char value
CHAR_MIN | –128 (0 if /J option used) | Minimum char value
MB_LEN_MAX | 2 | Maximum number of bytes in multibyte char

The following constants give the range and other characteristics of the double and float data types, and are defined in FLOAT.H:

Constant | Value | Description
DBL_DIG | 15 | # of decimal digits of precision
DBL_EPSILON | 2.2204460492503131e-016 | Smallest such that 1.0+DBL_EPSILON !=1.0
DBL_MANT_DIG | 53 | # of bits in mantissa
DBL_MAX | 1.7976931348623158e+308 | Maximum value
DBL_MAX_10_EXP | 308 | Maximum decimal exponent
DBL_MAX_EXP | 1024 | Maximum binary exponent
DBL_MIN | 2.2250738585072014e-308 | Minimum positive value
DBL_MIN_10_EXP | (-307) | Minimum decimal exponent
DBL_MIN_EXP | (–1021) | Minimum binary exponent
_DBL_RADIX | 2 | Exponent radix
_DBL_ROUNDS | 1 | Addition rounding: near
FLT_DIG | 6 | Number of decimal digits of precision
FLT_EPSILON | 1.192092896e-07F | Smallest such that 1.0+FLT_EPSILON !=1.0
FLT_MANT_DIG | 24 | Number of bits in mantissa
FLT_MAX | 3.402823466e+38F | Maximum value
FLT_MAX_10_EXP | 38 | Maximum decimal exponent
FLT_MAX_EXP | 128 | Maximum binary exponent
FLT_MIN | 1.175494351e-38F | Minimum positive value
FLT_MIN_10_EXP | (–37) | Minimum decimal exponent
FLT_MIN_EXP | (–125) | Minimum binary exponent
FLT_RADIX | 2 | Exponent radix
FLT_ROUNDS | 1 | Addition rounding: near


EOF, WEOF

Remarks

EOF is returned by an I/O routine when the end-of-file (or in some cases, an error) is encountered.

WEOF yields the return value, of type wint_t, used to signal the end of a wide stream, or to report an error condition.

See Also putc, ungetc, scanf, fflush, _fcloseall , _ungetch, _putch, __isascii


errno Constants

#include <errno.h>

Remarks

The errno values are constants assigned to errno in the event of various error conditions.

ERRNO.H contains the definitions of the errno values. However, not all the definitions given in ERRNO.H are used in 32-bit Windows operating systems. Some of the values in ERRNO.H are present to maintain compatibility with the UNIX family of operating systems.

The errno values in a 32-bit Windows operating system are a subset of the values for errno in XENIX systems. Thus, the errno value is not necessarily the same as the actual error code returned by a Windows NT or Windows 95 system call. To access the actual operating system error code, use the _doserrno variable, which contains this value.

The following errno values are supported:

ECHILD

No spawned processes.

EAGAIN

No more processes. An attempt to create a new process failed because there are no more process slots, or there is not enough memory, or the maximum nesting level has been reached.

E2BIG

Argument list too long.

EACCES

Permission denied. The file's permission setting does not allow the specified access. This error signifies that an attempt was made to access a file (or, in some cases, a directory) in a way that is incompatible with the file's attributes.

For example, the error can occur when an attempt is made to read from a file that is not open, to open an existing read-only file for writing, or to open a directory instead of a file. Under MS-DOS operating system versions 3.0 and later, EACCES may also indicate a locking or sharing violation.

The error can also occur in an attempt to rename a file or directory or to remove an existing directory.

EBADF

Bad file number. There are two possible causes: 1) The specified file handle is not a valid file-handle value or does not refer to an open file. 2) An attempt was made to write to a file or device opened for read-only access.

EDEADLOCK

Resource deadlock would occur. The argument to a math function is not in the domain of the function.

EDOM

Math argument.

EEXIST

Files exist. An attempt has been made to create a file that already exists. For example, the _O_CREAT and _O_EXCL flags are specified in an _open call, but the named file already exists.

EINVAL

Invalid argument. An invalid value was given for one of the arguments to a function. For example, the value given for the origin when positioning a file pointer (by means of a call to fseek) is before the beginning of the file.

EMFILE

Too many open files. No more file handles are available, so no more files can be opened.

ENOENT

No such file or directory. The specified file or directory does not exist or cannot be found. This message can occur whenever a specified file does not exist or a component of a path does not specify an existing directory.

ENOEXEC

Exec format error. An attempt was made to execute a file that is not executable or that has an invalid executable-file format.

ENOMEM

Not enough core. Not enough memory is available for the attempted operator. For example, this message can occur when insufficient memory is available to execute a child process, or when the allocation request in a _getcwd call cannot be satisfied.

ENOSPC

No space left on device. No more space for writing is available on the device (for example, when the disk is full).

ERANGE

Result too large. An argument to a math function is too large, resulting in partial or total loss of significance in the result. This error can also occur in other functions when an argument is larger than expected (for example, when the buffer argument to _getcwd is longer than expected).

EXDEV

Cross-device link. An attempt was made to move a file to a different device (using the rename function).


Exception-Handling Constants

Remarks

The constant EXCEPTION_CONTINUE_SEARCH, EXCEPTION_CONTINUE_EXECUTION, or EXCEPTION_EXECUTE_HANDLER is returned when an exception occurs during execution of the guarded section of a try-except statement. The return value determines how the exception is handled. For more information, see try-except Statement in the Language Quick Reference.


EXIT_SUCCESS, EXIT_FAILURE

#include <stdlib.h>

Remarks

These are arguments for the exit and _exit functions and the return values for the atexit and _onexit functions.

See Also atexit, exit, _onexit


File Attribute Constants

#include <io.h>

Remarks

These constants specify the current attributes of the file or directory specified by the function.

The attributes are represented by the following manifest constants:

_A_ARCH

Archive. Set whenever the file is changed, and cleared by the BACKUP command. Value: 0x20

_A_HIDDEN

Hidden file. Not normally seen with the DIR command, unless the /AH option is used. Returns information about normal files as well as files with this attribute. Value: 0x02

_A_NORMAL

Normal. File can be read or written to without restriction. Value: 0x00

_A_RDONLY

Read-only. File cannot be opened for writing, and a file with the same name cannot be created. Value: 0x01

_A_SUBDIR

Subdirectory. Value: 0x10

_A_SYSTEM

System file. Not normally seen with the DIR command, unless the /AS option is used. Value: 0x04

Multiple constants can be combined with the OR operator (|).

See Also _find Functions


File Constants

#include <fcntl.h>

Remarks

The integer expression formed from one or more of these constants determines the type of reading or writing operations permitted. It is formed by combining one or more constants with a translation-mode constant.

The file constants are as follows:

_O_APPEND

Repositions the file pointer to the end of the file before every write operation.

_O_CREAT

Creates and opens a new file for writing; this has no effect if the file specified by filename exists.

_O_EXCL

Returns an error value if the file specified by filename exists. Only applies when used with _O_CREAT.

_O_RDONLY

Opens file for reading only; if this flag is given, neither _O_RDWR nor _O_WRONLY can be given.

_O_RDWR

Opens file for both reading and writing; if this flag is given, neither _O_RDONLY nor _O_WRONLY can be given.

_O_TRUNC

Opens and truncates an existing file to zero length; the file must have write permission. The contents of the file are destroyed. If this flag is given, you cannot specify _O_RDONLY.

_O_WRONLY

Opens file for writing only; if this flag is given, neither _O_RDONLY nor _O_RDWR can be given.

See Also _open, _sopen


File Permission Constants

#include <sys/stat.h>

Remarks

One of these constants is required when _O_CREAT (_open, _sopen) is specified.

The pmode argument specifies the file's permission settings as follows.

Constant | Meaning
_S_IREAD | Reading permitted
_S_IWRITE | Writing permitted
_S_IREAD | _S_IWRITE | Reading and writing permitted

When used as the pmode argument for _umask, the manifest constant sets the permission setting, as follows.

Constant | Meaning
_S_IREAD | Writing not permitted (file is read-only)
_S_IWRITE | Reading not permitted (file is write-only)
_S_IREAD | _S_IWRITE | Neither reading nor writing permitted

See Also _open, _sopen, _umask, _stat structure


File Read/Write Access Constants

#include <stdio.h>

Remarks

These constants specify the access type ("a", "r", or "w") requested for the file. Both the translation mode ("b" or "t") and the commit-to-disk mode ("c" or "n") can be specified with the type of access.

The access types are described below.

"a"

Opens for writing at the end of the file (appending); creates the file first if it does not exist. All write operations occur at the end of the file. Although the file pointer can be repositioned using fseek or rewind, it is always moved back to the end of the file before any write operation is carried out.

"a+"

Same as above, but also allows reading.

"r"

Opens for reading. If the file does not exist or cannot be found, the call to open the file will fail.

"r+"

Opens for both reading and writing. If the file does not exist or cannot be found, the call to open the file will fail.

"w"

Opens an empty file for writing. If the given file exists, its contents are destroyed.

"w+"

Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

When the "r+", "w+", or "a+" type is specified, both reading and writing are allowed (the file is said to be open for "update"). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation.

See Also _fdopen, fopen, freopen, _fsopen, _popen


File Translation Constants

#include <stdio.h>

Remarks

These constants specify the mode of translation ("b" or "t"). The mode is included in the string specifying the type of access ("r", "w", "a", "r+", "w+", "a+").

The translation modes are as follows:

t

Opens in text (translated) mode. In this mode, carriage-return/linefeed (CR-LF) combinations are translated into single linefeeds (LF) on input, and LF characters are translated into CR-LF combinations on output. Also, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading or reading/writing, fopen checks for CTRL+Z at the end of the file and removes it, if possible. This is done because using the fseek and ftell functions to move within a file ending with CTRL+Z may cause fseek to behave improperly near the end of the file.

Note The t option is not part of the ANSI standard for fopen and freopen. It is a Microsoft extension and should not be used where ANSI portability is desired.

b

Opens in binary (untranslated) mode. The above translations are suppressed.

If t or b is not given in mode, the translation mode is defined by the default-mode variable _fmode. For more information about using text and binary modes, see Text and Binary Mode File I/O.

See Also _fdopen, fopen, freopen, _fsopen


FILENAME_MAX

#include <stdio.h>

Remarks

This is the maximum permissible length for filename.

See Also Path Field Limits


FOPEN_MAX, _SYS_OPEN

#include <stdio.h>

Remarks

This is the maximum number of files that can be opened simultaneously. FOPEN_MAX is the ANSI-compatible name. _SYS_OPEN is provided for compatibility with existing code.


_FREEENTRY, _USEDENTRY

#include <malloc.h>

Remarks

These constants represent values assigned by the _heapwalk routines to the _useflag element of the _HEAPINFO structure. They indicate the status of the heap entry.

See Also _heapwalk


fseek, _lseek Constants

#include <stdio.h>

Remarks

The origin argument specifies the initial position and can be one of the manifest constants shown below:

Constant | Meaning
SEEK_END | End of file
SEEK_CUR | Current position of file pointer
SEEK_SET | Beginning of file

See Also fseek, _lseek, _lseeki64


Heap Constants

#include <malloc.h>

Remarks

These constants give the return value indicating status of the heap.

Constant | Meaning
_HEAPBADBEGIN | Initial header information was not found or was invalid.
_HEAPBADNODE | Bad node was found, or heap is damaged.
_HEAPBADPTR | _pentry field of _HEAPINFO structure does not contain valid pointer into heap (_heapwalk routine only).
_HEAPEMPTY | Heap has not been initialized.
_HEAPEND | End of heap was reached successfully (_heapwalk routine only).
_HEAPOK | Heap is consistent (_heapset and _heapchk routines only). No errors so far; _HEAPINFO structure contains information about next entry (_heapwalk routine only).

See Also _heapchk, _heapset, _heapwalk


_HEAP_MAXREQ

#include <malloc.h>

Remarks

The maximum size of a user request for memory that can be granted.

See Also malloc, calloc


HUGE_VAL

#include <math.h>

Remarks

HUGE_VAL is the largest representable double value. This value is returned by many run-time math functions when an error occurs. For some functions, –HUGE_VAL is returned.


__LOCAL_SIZE

Remarks

The compiler provides a symbol, __LOCAL_SIZE, for use in the inline assembler block of function prolog code. This symbol is used to allocate space for local variables on the stack frame in your custom prolog code.

The compiler determines the value of __LOCAL_SIZE. Its value is the total number of bytes of all user-defined locals as well as compiler-generated temporary variables. __LOCAL_SIZE can be used as an immediate operand; it cannot be used in an expression. You must not change or redefine the value of this symbol. For example:

mov      eax, __LOCAL_SIZE           ;Immediate operand
mov      eax, [ebp - __LOCAL_SIZE]   ;Expression

The following is a example of a naked function containing custom prolog and epilog sequences using the __LOCAL_SIZE symbol in the prolog sequence:

__declspec ( naked ) func()
{
   int i;
   int j;

   _asm       /* prolog */
      {
      push      ebp
      mov      ebp, esp
      sub      esp, __LOCAL_SIZE
      }

   /* Function body */

   __asm      /* epilog */
      {
      mov      esp, ebp
      pop      ebp
      ret
      }
}

For related information, see naked in the Language Quick Reference.


Locale Categories

#include <locale.h>

Remarks

Locale categories are manifest constants used by the localization routines to specify which portion of a program's locale information will be used. The locale refers to the locality (or country) for which certain aspects of your program can be customized. Locale-dependent areas include, for example, the formatting of dates or the display format for monetary values.

Locale Category | Parts of Program Affected
LC_ALL | All locale-specific behavior (all categories)
LC_COLLATE | Behavior of strcoll and strxfrm functions
LC_CTYPE | Behavior of character-handling functions (except isdigit, isxdigit, mbstowcs, and mbtowc, which are unaffected)
LC_MAX | Same as LC_TIME
LC_MIN | Same as LC_ALL
LC_MONETARY | Monetary formatting information returned by the localeconv function
LC_NUMERIC | Decimal-point character for formatted output routines (for example, printf), data conversion routines, and nonmonetary formatting information returned by localeconv function
LC_TIME | Behavior of strftime function

See Also localeconv, setlocale, strcoll Functions, strftime, strxfrm


_locking Constants

#include <sys/locking.h>

Remarks

The mode argument in the call to the _locking function specifies the locking action to be performed.

The mode argument must be one of the following manifest constants:

_LK_LOCK

Locks the specified bytes. If the bytes cannot be locked, the function tries again after one second. If, after ten attempts, the bytes cannot be locked, the function returns an error.

_LK_RLCK

Same as _LK_LOCK.

_LK_NBLCK

Locks the specified bytes. If bytes cannot be locked, the function returns an error.

_LK_NBRLCK

Same as _LK_NBLCK.

_LK_UNLCK

Unlocks the specified bytes. (The bytes must have been previously locked.)

See Also _locking


Math Error Constants

#include <math.h>

Remarks

The math routines of the run-time library can generate math error constants.

These errors, described as follows, correspond to the exception types defined in MATH.H and are returned by the _matherr function when a math error occurs.

Constant | Meaning
_DOMAIN | Argument to function is outside domain of function.
_OVERFLOW | Result is too large to be represented in function's return type.
_PLOSS | Partial loss of significance occurred.
_SING | Argument singularity: argument to function has illegal value. (For example, value 0 is passed to function that requires nonzero value.)
_TLOSS | Total loss of significance occurred.
_UNDERFLOW | Result is too small to be represented.

See Also _matherr


MB_CUR_MAX

#include <stdlib.h>

Context: ANSI multibyte- and wide-character conversion functions

Remarks

The value of MB_CUR_MAX is the maximum number of bytes in a multibyte character for the current locale.

See Also mblen, mbstowcs, mbtowc, wchar_t, wcstombs, wctomb, Data Type Constants


NULL

Remarks

NULL is the null-pointer value used with many pointer operations and functions.


Path Field Limits

#include <stdlib.h>

Remarks

These constants define the maximum length for the path and for the individual fields within the path.

Constant | Meaning
_MAX_DIR | Maximum length of directory component
_MAX_DRIVE | Maximum length of drive component
_MAX_EXT | Maximum length of extension component
_MAX_FNAME | Maximum length of filename component
_MAX_PATH | Maximum length of full path

The sum of the fields should not exceed _MAX_PATH.


RAND_MAX

#include <stdlib.h>

Remarks

The constant RAND_MAX is the maximum value that can be returned by the rand function. RAND_MAX is defined as the value 0x7fff.

See Also rand


setvbuf Constants

#include <stdio.h>

Remarks

These constants represent the type of buffer for setvbuf.

The possible values are given by the following manifest constants:

Constant | Meaning
_IOFBF | Full buffering: Buffer specified in call to setvbuf is used and its size is as specified in setvbuf call. If buffer pointer is NULL, automatically allocated buffer of specified size is used.
_IOLBF | Same as _IOFBF.
_IONBF | No buffer is used, regardless of arguments in call to setvbuf.

See Also setbuf


Sharing Constants

#include <share.h>

Remarks

The shflag argument determines the sharing mode, which consists of one or more manifest constants. These can be combined with the oflag arguments (see File Constants).

The constants and their meanings are listed below:

Constant | Meaning
_SH_COMPAT | Sets compatibility mode
_SH_DENYRW | Denies read and write access to file
_SH_DENYWR | Denies write access to file
_SH_DENYRD | Denies read access to file
_SH_DENYNO | Permits read and write access

See Also _sopen, _fsopen


signal Constants

#include <signal.h>

Remarks

The sig argument must be one of the manifest constants listed below (defined in SIGNAL.H).

SIGABRT

Abnormal termination. The default action terminates the calling program with exit code 3.

SIGFPE

Floating-point error, such as overflow, division by zero, or invalid operation. The default action terminates the calling program.

SIGILL

Illegal instruction. The default action terminates the calling program.

SIGINT

CTRL+C interrupt. The default action issues INT 23H.

SIGSEGV

Illegal storage access. The default action terminates the calling program.

SIGTERM

Termination request sent to the program. The default action terminates the calling program.

See Also signal, raise


signal Action Constants

#include <signal.h>

Remarks

The action taken when the interrupt signal is received depends on the value of func.

The func argument must be either a function address or one of the manifest constants listed below and defined in SIGNAL.H.

SIG_DFL

Uses system-default response. If the calling program uses stream I/O, buffers created by the run-time library are not flushed.

SIG_IGN

Ignores interrupt signal. This value should never be given for SIGFPE, since the floating-point state of the process is left undefined.

See Also signal


_spawn Constants

#include <process.h>

Remarks

The mode argument determines the action taken by the calling process before and during a spawn operation. The following values for mode are possible:

Constant | Meaning
_P_OVERLAY | Overlays calling process with new process, destroying calling process (same effect as _exec calls).
_P_WAIT | Suspends calling thread until execution of new process is complete (synchronous _spawn).
_P_NOWAIT or _P_NOWAITO | Continues to execute calling process concurrently with new process (asynchronous _spawn, valid only in 32-bit Windows applications).
_P_DETACH | Continues to execute calling process; new process is run in background with no access to console or keyboard. Calls to _cwait against new process will fail. This is an asynchronous _spawn and is valid only in 32-bit Windows applications.

See Also _spawn Functions


_stat Structure st_mode Field Constants

#include <sys/stat.h>

Remarks

These constants are used to indicate file type in the st_mode field of the _stat structure.

The bit mask constants are described below:

Constant | Meaning
_S_IFMT | File type mask
_S_IFDIR | Directory
_S_IFCHR | Character special (indicates a device if set)
_S_IFREG | Regular
_S_IREAD | Read permission, owner
_S_IWRITE | Write permission, owner
_S_IEXEC | Execute/search permission, owner

See Also _stat, _fstat, Standard Types


stdin, stdout, stderr

FILE *stdin;

FILE *stdout;

FILE *stderr;

#include <stdio.h>

Remarks

These are standard streams for input, output, and error output.

By default, standard input is read from the keyboard, while standard output and standard error are printed to the screen.

The following stream pointers are available to access the standard streams:

Pointer | Stream
stdin | Standard input
stdout | Standard output
stderr | Standard error

These pointers can be used as arguments to functions. Some functions, such as getchar and putchar, use stdin and stdout automatically.

These pointers are constants, and cannot be assigned new values. The freopen function can be used to redirect the streams to disk files or to other devices. The operating system allows you to redirect a program's standard input and output at the command level.

Stream I/O


TMP_MAX, L_tmpnam

#include <stdio.h>

Remarks

TMP_MAX is the maximum number of unique filenames that the tmpnam function can generate. L_tmpnam is the length of temporary filenames generated by tmpnam.


Translation Mode Constants

#include <fcntl.h>

Remarks

The _O_BINARY and _O_TEXT manifest constants determine the translation mode for files (_open and _sopen) or the translation mode for streams (_setmode).

The allowed values are:

_O_TEXT

Opens file in text (translated) mode. Carriage return – linefeed (CR-LF) combinations are translated into a single linefeed (LF) on input. Linefeed characters are translated into CR-LF combinations on output. Also, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading and reading/writing, fopen checks for CTRL+Z at the end of the file and removes it, if possible. This is done because using the fseek and ftell functions to move within a file ending with CTRL+Z may cause fseek to behave improperly near the end of the file.

_O_BINARY

Opens file in binary (untranslated) mode. The above translations are suppressed.

_O_RAW

Same as _O_BINARY. Supported for C 2.0 compatibility.

For more information, see Text and Binary Mode File I/O and File Translation.

See Also _open, _pipe, _sopen, _setmode


_WAIT_CHILD, _WAIT_GRANDCHILD

#include <process.h>

Remarks

The _cwait function can be used by any process to wait for any other process (if the process ID is known). The action argument can be one of the following values:

Constant | Meaning
_WAIT_CHILD | Calling process waits until specified new process terminates.
_WAIT_GRANDCHILD | Calling process waits until specified new process, and all processes created by that new process, terminate.

See Also _cwait


32-bit Windows Time/Date Formats

Remarks

The file time and the date are stored individually, using unsigned integers as bit fields. File time and date are packed as follows:

Time

Bit Position: | 0 1 2 3 4 | 5 6 7 8 9 A | B C D E F
Length: | 5 | 6 | 5
Contents: | hours | minutes | 2-second increments
Value Range: | 0–23 | 0–59 | 0–29 in 2-second intervals

Date

Bit Position: | 0 1 2 3 4 5 6 | 7 8 9 A | B C D E F
Length: | 7 | 4 | 5
Contents: | year | month | day
Value Range: | 0–119 | 1–12 | 1–31
 | (relative to 1980) |  |


_ASSERT, _ASSERTE Macros

Evaluate an expression and generate a debug report when the result is FALSE (debug version only).

_ASSERT( booleanExpression );

_ASSERTE( booleanExpression );

Macro | Required Header | Compatibility
_ASSERT | <crtdbg.h> | Win NT, Win 95
_ASSERTE | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Although _ASSERT and _ASSERTE are macros and are obtained by including CRTDBG.H, the application must link with one of the libraries listed above because these macros call other run-time functions.

Return Value

None

Parameter

booleanExpression

Expression (including pointers) that evaluates to nonzero or 0

Remarks

The _ASSERT and _ASSERTE macros provide an application with a clean and simple mechanism for checking assumptions during the debugging process. They are very flexible because they do not need to be enclosed in #ifdef statements to prevent them from being called in a retail build of an application. This flexibility is achieved by using the _DEBUG macro. _ASSERT and _ASSERTE are only available when _DEBUG is defined. When _DEBUG is not defined, calls to these macros are removed during preprocessing.

_ASSERT and _ASSERTE evaluate their booleanExpression argument and when the result is FALSE (0), they print a diagnostic message and call _CrtDbgReport to generate a debug report. The _ASSERT macro prints a simple diagnostic message, while _ASSERTE includes a string representation of the failed expression in the message. These macros do nothing when booleanExpression evaluates to nonzero.

Because the _ASSERTE macro specifies the failed expression in the generated report, it enables users to identify the problem without referring to the application source code. However, a disadvantage exists in that every expression evaluated by _ASSERTE must be included in the debug version of your application as a string constant. Therefore, if a large number of calls are made to _ASSERTE, these expressions can take up a significant amount of space.

_CrtDbgReport generates the debug report and determines its destination(s), based on the current report mode(s) and file defined for the _CRT_ASSERT report type. By default, assertion failures and errors are directed to a debug message window. The _CrtSetReportMode and _CrtSetReportFile functions are used to define the destination(s) for each report type.

When the destination is a debug message window and the user chooses the Retry button, _CrtDbgReport returns 1, causing the _ASSERT and _ASSERTE macros to start the debugger, provided that “just-in-time” (JIT) debugging is enabled. See Debug Reporting Functions of the C Run-Time Library for an example of an assert message box under Windows NT.

For more information about the reporting process, see the _CrtDbgReport function and the section Debug Reporting Functions of the C Run-Time Library. For more information about resolving assertion failures and using these macros as a debugging error handling mechanism, see Using Macros for Verification and Reporting.

The _RPT, _RPTF debug macros are also available for generating a debug report, but they do not evaluate an expression. The _RPT macros generate a simple report and the _RPTF macros include the source file and line number where the report macro was called, in the generated report. In addition to the _ASSERTE macros, the ANSI assert routine can also be used to verify program logic. This routine is available in both the debug and release versions of the libraries.

Example

/*

 * DBGMACRO.C

 * In this program, calls are made to the _ASSERT and _ASSERTE

 * macros to test the condition 'string1 == string2'.  If the

 * condition fails, these macros print a diagnostic message.

 * The _RPTn and _RPTFn group of macros are also exercised in

 * this program, as an alternative to the printf function.

 */

#include <stdio.h>

#include <string.h>

#include <malloc.h>

#include <crtdbg.h>

int main()

{

char *p1, *p2;

/*

* The Reporting Mode and File must be specified

* before generating a debug report via an assert

* or report macro.

* This program sends all report types to STDOUT

*/

_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);

_CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);

_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);

_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);

_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);

_CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

/*

* Allocate and assign the pointer variables

*/

p1 = (char *)malloc(10);

strcpy(p1, "I am p1");

p2 = (char *)malloc(10);

strcpy(p2, "I am p2");

/*

* Use the report macros as a debugging

* warning mechanism, similar to printf.

*

* Use the assert macros to check if the

* p1 and p2 variables are equivalent.

*

* If the expression fails, _ASSERTE will

* include a string representation of the

* failed expression in the report.

* _ASSERT does not include the

* expression in the generated report.

*/

_RPT0(_CRT_WARN, "\n\n Use the assert macros to evaluate the expression p1 == p2.\n");

_RPTF2(_CRT_WARN, "\n Will _ASSERT find '%s' == '%s' ?\n", p1, p2);

_ASSERT(p1 == p2);

_RPTF2(_CRT_WARN, "\n\n Will _ASSERTE find '%s' == '%s' ?\n", p1, p2);

_ASSERTE(p1 == p2);

_RPT2(_CRT_ERROR, "\n \n '%s' != '%s'\n", p1, p2);

free(p2);

free(p1);

return 0;

}

Output

Use the assert macros to evaluate the expression p1 == p2.

dbgmacro.c(54) : Will _ASSERT find 'I am p1' == 'I am p2' ?
dbgmacro.c(55) : Assertion failed

dbgmacro.c(57) : Will _ASSERTE find 'I am p1' == 'I am p2' ?
dbgmacro.c(58) : Assertion failed: p1 == p2

'I am p1' != 'I am p2'

Debug Functions

See Also   _RPT, _RPTF


_calloc_dbg

Allocates a number of memory blocks in the heap with additional space for a debugging header and overwrite buffers (debug version only).

void *_calloc_dbg( size_t num, size_t size, int blockType, const char *filename, int linenumber );

Routine | Required Header | Compatibility
_calloc_dbg | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

Upon successful completion, this function either returns a pointer to the user portion of the last allocated memory block, calls the new handler function, or returns NULL. See the following Remarks section for a complete description of the return behavior. See the calloc function for more information on how the new handler function is used.

Parameters

num

Requested number of memory blocks

size

Requested size of each memory block (bytes)

blockType

Requested type of memory block: _CLIENT_BLOCK or _NORMAL_BLOCK

filename

Pointer to name of source file that requested allocation operation or NULL

linenumber

Line number in source file where allocation operation was requested or NULL

The filename and linenumber parameters are only available when _calloc_dbg has been called explicitly or the _CRTDBG_MAP_ALLOC preprocessor constant has been defined.

Remarks

_calloc_dbg is a debug version of the calloc function. When _DEBUG is not defined, calls to _calloc_dbg are removed during preprocessing. Both calloc and _calloc_dbg allocate num memory blocks in the base heap, but _calloc_dbg offers several debugging features: buffers on either side of the user portion of the block to test for leaks, a block type parameter to track specific allocation types, and filename/linenumber information to determine the origin of allocation requests.

_calloc_dbg allocates each memory block with slightly more space than the requested size. The additional space is used by the debug heap manager to link the debug memory blocks together and to provide the application with debug header information and overwrite buffers. When the block is allocated, the user portion of the block is filled with the value 0xCD and each of the overwrite buffers are filled with 0xFD.

For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap. For information about the allocation block types and how they are used, see Types of Blocks on the Debug Heap. For information on the differences between calling a standard heap function versus its debug version in a debug build of an application, see Using the Debug Version Versus the Base Version.

Example

/*
 * CALLOCD.C
 * This program uses _calloc_dbg to allocate space for
 * 40 long integers. It initializes each element to zero.
 */
#include <stdio.h>
#include <malloc.h>
#include <crtdbg.h>

void main( void )
{
        long *bufferN, *bufferC;

        /*
         * Call _calloc_dbg to include the filename and line number
         * of our allocation request in the header and also so we can
         * allocate CLIENT type blocks specifically
         */
        bufferN = (long *)_calloc_dbg( 40, sizeof(long), _NORMAL_BLOCK, __FILE__, __LINE__ );
        bufferC = (long *)_calloc_dbg( 40, sizeof(long), _CLIENT_BLOCK, __FILE__, __LINE__ );
        if( bufferN != NULL && bufferC != NULL )
              printf( "Allocated memory successfully\n" );
        else
              printf( "Problem allocating memory\n" );

        /*
         * _free_dbg must be called to free CLIENT type blocks
         */
        free( bufferN );
        _free_dbg( bufferC, _CLIENT_BLOCK );
}

Output

Allocated memory successfully

Debug Functions

See Also calloc, _malloc_dbg, _DEBUG


_CrtCheckMemory

Confirms the integrity of the memory blocks allocated in the debug heap (debug version only).

int _CrtCheckMemory( void );

Routine | Required Header | Compatibility
_CrtCheckMemory | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

If successful, _CrtCheckMemory returns TRUE; otherwise, the function returns FALSE.

Remarks

The _CrtCheckMemory function validates memory allocated by the debug heap manager by verifying the underlying base heap and inspecting every memory block. If an error or memory inconsistency is encountered in the underlying base heap, the debug header information, or the overwrite buffers, _CrtCheckMemory generates a debug report with information describing the error condition. When _DEBUG is not defined, calls to _CrtCheckMemory are removed during preprocessing.

The behavior of _CrtCheckMemory can be controlled by setting the bit fields of the _crtDbgFlag flag using the _CrtSetDbgFlag function. Turning the _CRTDBG_CHECK_ALWAYS_DF bit field ON results in _CrtCheckMemory being called every time a memory allocation operation is requested. Although this method slows down execution, it is useful for catching errors quickly. Turning the _CRTDBG_ALLOC_MEM_DF bit field OFF causes _CrtCheckMemory to not verify the heap and immediately return TRUE.

Because this function returns TRUE or FALSE, it can be passed to one of the _ASSERT macros to create a simple debugging error handling mechanism. The following example will cause an assertion failure if corruption is detected in the heap:

_ASSERTE( _CrtCheckMemory( ) );

For more information about how _CrtCheckMemory can be used with other debug functions, see Heap State Reporting Functions. For an overview of memory management and the debug heap, see Memory Management and the Debug Heap.

Example

/*****************************************************************
 *  EXAMPLE  1                                                   *
 *  This simple program illustrates the basic debugging features *
 *  of the C runtime libraries, and the kind of debug output     *
 *  that these features generate.                                *
 *****************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

// This routine place comments at the head of a section of debug output
void OutputHeading( const char * explanation )
{
   _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}

// The following macros set and clear, respectively, given bits
// of the C runtime library debug flag, as specified by a bitmask.
#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

void main( )
{
   char *p1, *p2;
   _CrtMemState s1, s2, s3;

   // Send all reports to STDOUT
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );

   // Allocate 2 memory blocks and store a string in each
   p1 = malloc( 34 );
   strcpy( p1, "This is the p1 string (34 bytes)." );

   p2 = malloc( 34 );
   strcpy( p2, "This is the p2 string (34 bytes)." );

   OutputHeading(
      "Use _ASSERTE to check that the two strings are identical" );
   _ASSERTE( strcmp( p1, p2 ) == 0 );

   OutputHeading(
      "Use a _RPT macro to report the string contents as a warning" );
   _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );

   OutputHeading(
      "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
   _CrtMemDumpAllObjectsSince( NULL );

   free( p2 );

   OutputHeading(
      "Having freed p2, dump allocation information about p1 only" );
   _CrtMemDumpAllObjectsSince( NULL );

   // Store a memory checkpoint in the s1 memory-state structure
   _CrtMemCheckpoint( &s1 );

   // Allocate another block, pointed to by p2
   p2 = malloc( 38 );
   strcpy( p2, "This new p2 string occupies 38 bytes.");

   // Store a 2nd memory checkpoint in s2
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Dump the changes that occurred between two memory checkpoints" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   // Free p2 again and store a new memory checkpoint in s2
   free( p2 );
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Now the memory state at the two checkpoints is the same" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   strcpy( p1, "This new p1 string is over 34 bytes" );
   OutputHeading( "Free p1 after overwriting the end of the allocation" );
   free( p1 );

   // Set the debug-heap flag so that freed blocks are kept on the
   // linked list, to catch any inadvertent use of freed memory
   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );

   p1 = malloc( 10 );
   free( p1 );
   strcpy( p1, "Oops" );

   OutputHeading( "Perform a memory check after corrupting freed memory" );
   _CrtCheckMemory( );

   // Use explicit calls to _malloc_dbg to save file name and line number
   // information, and also to allocate Client type blocks for tracking
   p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
   p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
   strcpy( p1, "p1 points to a Normal allocation block" );
   strcpy( p2, "p2 points to a Client allocation block" );

   // You must use _free_dbg to free a Client block
   OutputHeading(
      "Using free( ) to free a Client block causes an assertion failure" );
   free( p1 );
   free( p2 );

   p1 = malloc( 10 );
   OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
   _CrtDumpMemoryLeaks( );

   // Set the debug-heap flag so that memory leaks are reported when
   // the process terminates. Then, exit.
   OutputHeading( "Program exits without freeing a memory block" );
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

Output

Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0

Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'

Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
 Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.

Now the memory state at the two checkpoints is the same:
**************************************************************************

Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.

Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.

Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse

Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Debug Functions

See Also _crtDbgFlag, _CrtSetDbgFlag


_CrtDbgReport

Generates a report with a debugging message and sends the report to three possible destinations (debug version only).

int _CrtDbgReport( int reportType, const char *filename, int linenumber, const char *moduleName, const char *format [, argument] ... );

Routine | Required Header | Compatibility
_CrtDbgReport | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

For all report destinations, _CrtDbgReport returns –1 if an error occurs and 0 if no errors are encountered. However, when the report destination is a debug message window and the user chooses the Retry button, _CrtDbgReport returns 1. If the user chooses the Abort button in the debug message window, _CrtDbgReport immediately aborts and does not return a value.

The _ASSERT[E] and _RPT, _RPTF debug macros call _CrtDbgReport to generate their debug report. When _CrtDbgReport returns 1, these macros start the debugger, provided that “just-in-time” (JIT) debugging is enabled.

Parameters

reportType

Report type: _CRT_WARN, _CRT_ERROR, _CRT_ASSERT

filename

Pointer to name of source file where assert/report occurred or NULL

linenumber

Line number in source file where assert/report occured or NULL

moduleName

Pointer to name of module (.EXE or .DLL) where assert/report occurred

format

Pointer to format-control string used to create the user message

argument

Optional substitution arguments used by format

Remarks

The _CrtDbgReport function is similar to the printf function, as it can be used to report warnings, errors, and assert information to the user during the debugging process. However, this function is more flexible than printf because it does not need to be enclosed in #ifdef statements to prevent it from being called in a retail build of an application. This is achieved by using the _DEBUG flag: When _DEBUG is not defined, calls to _CrtDbgReport are removed during preprocessing.

_CrtDbgReport can send the debug report to three different destinations: a debug report file, a debug monitor (the Visual C++ debugger), or a debug message window. Two configuration functions, _CrtSetReportMode and _CrtSetReportFile, are used to specify the destination(s) for each report type. These functions allow the reporting destination(s) for each report type to be separately controlled. For example, it is possible to specify that a reportType of _CRT_WARN only be sent to the debug monitor, while a reportType of _CRT_ASSERT be sent to a debug message window and a user-defined report file.

_CrtDbgReport creates the user message for the debug report by substituting the argument[n] arguments into the format string, using the same rules defined by the printf function. _CrtDbgReport then generates the debug report and determines the destination(s), based on the current report modes and file defined for reportType. When the report is sent to a debug message window, the filename, lineNumber, and moduleName are included in the information displayed in the window.

The following table lists the available choices for the report mode(s) and file and the resulting behavior of _CrtDbgReport. These options are defined as bit-flags in CRTDBG.H.

Report Mode | Report File | _CrtDbgReport Behavior
_CRTDBG_- MODE_DEBUG | Not applicable | Writes message to Windows OutputDebugString API.
_CRTDBG_- MODE_WNDW | Not applicable | Calls Windows MessageBox API to create message box to display the message along with Abort, Retry, and Ignore buttons. If user selects Abort, _CrtDbgReport immediately aborts. If user selects Retry, it returns 1. If user selects Ignore, execution continues and _CrtDbgReport returns 0. Note that choosing Ignore when an error condition exists often results in “undefined behavior.”
_CRTDBG_- MODE_FILE | __HFILE | Writes message to user-supplied HANDLE, using the Windows WriteFile API, and does not verify validity of file handle; the application is responsible for opening the report file and passing a valid file handle.
_CRTDBG_- MODE_FILE | _CRTDBG_- FILE_STDERR | Writes message to stderr.
_CRTDBG_- MODE_FILE | _CRTDBG_- FILE_STDOUT | Writes message to stdout.

The report may be sent to one, two, or three destinations, or no destination at all. For more information about specifying the report mode(s) and report file, see the _CrtSetReportMode and _CrtSetReportFile functions. For more information about using the debug macros and reporting functions, see Using Macros for Verification and Reporting and Debug Reporting Functions of the C Run-Time Library.

If your application needs more flexibility than that provided by _CrtDbgReport, you can write your own reporting function and hook it into the C run-time library reporting mechanism by using the _CrtSetReportHook function.

Example

/*
 * REPORT.C:
 * In this program, calls are made to the _CrtSetReportMode,
 * _CrtSetReportFile, and _CrtSetReportHook functions.
 * The _ASSERT macros are called to evaluate their expression.
 * When the condition fails, these macros print a diagnostic message
 * and call _CrtDbgReport to generate a debug report and the
 * client-defined reporting function is called as well.
 * The _RPTn and _RPTFn group of macros are also exercised in
 * this program, as an alternative to the printf function.
 * When these macros are called, the client-defined reporting function
 * takes care of all the reporting - _CrtDbgReport won't be called.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

#define FALSE 0
#define TRUE !FALSE

/*
 * Define our own reporting function.
 * We'll hook it into the debug reporting
 * process later using _CrtSetReportHook.
 *
 * Define a global int to keep track of
 * how many assertion failures occur.
 */
int gl_num_asserts=0;
int OurReportingFunction( int reportType, char *userMessage, int *retVal )
{
   /*
    * Tell the user our reporting function is being called.
    * In other words - verify that the hook routine worked.
    */
   fprintf(stdout, "Inside the client-defined reporting function.\n");
   fflush(stdout);

   /*
    * When the report type is for an ASSERT,
    * we'll report some information, but we also
    * want _CrtDbgReport to get called -
    * so we'll return TRUE.
    *
    * When the report type is a WARNing or ERROR,
    * we'll take care of all of the reporting. We don't
    * want _CrtDbgReport to get called -
    * so we'll return FALSE.
    */
   if (reportType == _CRT_ASSERT)
   {
      gl_num_asserts++;
      fprintf(stdout, "This is the number of Assertion failures that have occurred: %d \n", gl_num_asserts);
      fflush(stdout);
      fprintf(stdout, "Returning TRUE from the client-defined reporting function.\n");
      fflush(stdout);
      return(TRUE);
   } else {
      fprintf(stdout, "This is the debug user message: %s \n", userMessage);
      fflush(stdout);
      fprintf(stdout, "Returning FALSE from the client-defined reporting function.\n");
      fflush(stdout);
      return(FALSE);
   }

   /*
    * By setting retVal to zero, we are instructing _CrtDbgReport
    * to continue with normal execution after generating the report.
    * If we wanted _CrtDbgReport to start the debugger, we would set
    * retVal to one.
    */
   retVal = 0;
}

int main()
{
      char *p1, *p2;

   /*
    * Hook in our client-defined reporting function.
    * Every time a _CrtDbgReport is called to generate
    * a debug report, our function will get called first.
    */
   _CrtSetReportHook( OurReportingFunction );

   /*
    * Define the report destination(s) for each type of report
    * we are going to generate.  In this case, we are going to
    * generate a report for every report type: _CRT_WARN,
    * _CRT_ERROR, and _CRT_ASSERT.
    * The destination(s) is defined by specifying the report mode(s)
    * and report file for each report type.
    * This program sends all report types to stdout.
    */
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   /*
    * Allocate and assign the pointer variables
    */
   p1 = malloc(10);
   strcpy(p1, "I am p1");
   p2 = malloc(10);
   strcpy(p2, "I am p2");

   /*
    * Use the report macros as a debugging
    * warning mechanism, similar to printf.
    *
    * Use the assert macros to check if the
    * p1 and p2 variables are equivalent.
    *
    * If the expression fails, _ASSERTE will
    * include a string representation of the
    * failed expression in the report.
    *
    *  _ASSERT does not include the
    * expression in the generated report.
    */
   _RPT0(_CRT_WARN, "\n\n Use the assert macros to evaluate the expression p1 == p2.\n");
   _RPTF2(_CRT_WARN, "\n Will _ASSERT find '%s' == '%s' ?\n", p1, p2);
   _ASSERT(p1 == p2);

   _RPTF2(_CRT_WARN, "\n\n Will _ASSERTE find '%s' == '%s' ?\n", p1, p2);
   _ASSERTE(p1 == p2);

   _RPT2(_CRT_ERROR, "\n \n '%s' != '%s'\n", p1, p2);

   free(p2);
   free(p1);

   return 0;
}

Output

Inside the client-defined reporting function.
This is the debug user message: Use the assert macros to evaluate the expression p1 == p2
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(54) : Will _ASSERT find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 1
Returning TRUE from the client-defined reporting function.
dbgmacro.c(55) : Assertion failed
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(57) : Will _ASSERTE find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 2
Returning TRUE from the client-defined reporting function.
dbgmacro.c(58) : Assertion failed: p1 == p2
Inside the client-defined reporting function.
This is the debug user message: 'I am p1' != 'I am p2'
Returning FALSE from the client-defined reporting function.

Debug Functions

See Also _CrtSetReportMode, _CrtSetReportFile, printf, _DEBUG


_CrtDoForAllClientObjects

Calls an application-supplied function for all _CLIENT_BLOCK types in the heap (debug version only).

void _CrtDoForAllClientObjects( void (*pfn)(void *, void *), void *context );

Routine | Required Header | Compatibility
_CrtDoForAllClientObjects | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

None

Parameters

void (*pfn)(void *, void *)

Pointer to the application-supplied function to call

context

Pointer to the application-supplied context to pass to the application-supplied function

Remarks

The _CrtDoForAllClientObjects function searches the heap’s linked list for memory blocks with the _CLIENT_BLOCK type and calls the application-supplied function when a block of this type is found. The found block and the context parameter are passed as arguments to the application-supplied function. During debugging, an application can track a specific group of allocations by explicitly calling the debug heap functions to allocate the memory and specifying that the blocks be assigned the _CLIENT_BLOCK block type. These blocks can then be tracked separately and reported on differently during leak detection and memory state reporting.

If the _CRTDBG_ALLOC_MEM_DF bit field of the _crtDbgFlag flag is not turned on, _CrtDoForAllClientObjects immediately returns. When _DEBUG is not defined, calls to _CrtDoForAllClientObjects are removed during preprocessing.

For more information about the _CLIENT_BLOCK type and how it can be used by other debug functions, see Types of Blocks on the Debug Heap. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*
 * DFACOBJS.C
 * This program allocates some CLIENT type blocks of memory
 * and then calls _CrtDoForAllClientObjects to print out the contents
 * of each client block found on the heap.
 */

#include <crtdbg.h>
#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

/*
 * My Memory Block linked-list data structure
 */
typedef struct MyMemoryBlockStruct
{
   struct MyMemoryBlockStruct *NextPtr;
   int blockType;
   int allocNum;
} aMemoryBlock;
aMemoryBlock *HeadPtr;
aMemoryBlock *TailPtr;

/*
 * CreateMemoryBlock
 * allocates a block of memory, fills in the data structure
 * and adds the new block to the linked list
 * Returns 1 if successful, otherwise 0
 */
int CreateMemoryBlock(
   int allocNum,
   int blockType
   )
{
   aMemoryBlock *blockPtr;
   size_t size;

   size = sizeof( struct MyMemoryBlockStruct );
   if ( blockType == _CLIENT_BLOCK )
      blockPtr = (aMemoryBlock *) _malloc_dbg( size, _CLIENT_BLOCK, __FILE__, __LINE__ );
   else
      blockPtr = (aMemoryBlock *) _malloc_dbg( size, _NORMAL_BLOCK, __FILE__, __LINE__ );

   if ( blockPtr == NULL )
      return(0);

   blockPtr->allocNum = allocNum;
   blockPtr->blockType = blockType;

   blockPtr->NextPtr = NULL;
   if ( HeadPtr == NULL )
      HeadPtr = blockPtr;
   else
      TailPtr->NextPtr = blockPtr;
   TailPtr = blockPtr;
   return(1);
}

/*
 * RestoreMemoryToHeap
 * restores all of the memory that we allocated on the heap
 */
void RestoreMemoryToHeap( )
{
   aMemoryBlock *blockPtr;

   if (!HeadPtr)
      return;

   while ( HeadPtr->NextPtr != NULL )
   {
      blockPtr = HeadPtr->NextPtr;
      if  ( HeadPtr->blockType == _CLIENT_BLOCK )
         _free_dbg( HeadPtr, _CLIENT_BLOCK );
      else
         _free_dbg( HeadPtr, _NORMAL_BLOCK );

      HeadPtr = blockPtr;
   }
}

/*
 * MyClientObjectHook
 * A hook function for performing some action on all
 * client blocks found on the heap - In this case, print
 * out the value stored at each memory address.
 */
void __cdecl MyClientObjectHook(
   void * pUserData,
   void * ignored
   )
{
   aMemoryBlock *blockPtr;
   long allocReqNum;
   int success;

   blockPtr = (aMemoryBlock *) pUserData;

   /*
    * Let's retrieve the actual object allocation order request number
    * and see if it's different from the allocation number we stored in
    * in our data structure.
    */
   success = _CrtIsMemoryBlock((const void *) blockPtr,
            (unsigned int) sizeof( struct MyMemoryBlockStruct ), &allocReqNum,
            NULL, NULL );
   if ( success )
   printf( "Block #%d \t Type: %d \t Allocation Number: %d\n", blockPtr->allocNum,
           blockPtr->blockType, allocReqNum);
   else
   {
          printf("ERROR: not a valid memory block.\n");
          exit( 1 );
   }
}

void main( void )
{
   div_t div_result;
   int i, success, tmpFlag;

   /*
    * Set the _crtDbgFlag to turn debug type allocations.
    * This will enable us to specify that blocks of type
    * _CLIENT_BLOCK can be allocated and tracked separately.
    * Turn off checking for internal CRT blocks.
    */
   tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
   tmpFlag |= _CRTDBG_ALLOC_MEM_DF;
   tmpFlag &= _CRTDBG_CHECK_CRT_DF;
   _CrtSetDbgFlag( tmpFlag );

   /*
    * We're going to allocate 22 blocks and every other block is
    * going to be of type _CLIENT_BLOCK.
    * Blocks numbered 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, and 22
    * should all be _CLIENT_BLOCKS.
    */
   HeadPtr = NULL;
   printf("Allocating the memory ");
   for (i=1; i < 23; i++)
   {
          div_result = div( i, 2);
   if ( div_result.rem > 0 )
      success = CreateMemoryBlock( i, _NORMAL_BLOCK );
   else
      success = CreateMemoryBlock( i, _CLIENT_BLOCK );

   if ( !success )
   {
         printf(" ERROR.\n");
            exit( 1 );
      }
   else
      printf(".");
   }
   printf(" done.\n");

   /*
    * We're going to call _CrtDoForAllClientObjects to
    * make sure that only blocks numbered 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, and 22
    * got allocated as _CLIENT_BLOCKS.
    */
   _CrtDoForAllClientObjects( MyClientObjectHook, NULL );

   /*
    * Restore the memory to the heap
    */
   RestoreMemoryToHeap();
   exit( 0 );
}

Output

The instruction at "0x00401153" referenced memory at "0x00000004". The memory could not be "read".

Debug Functions

See Also _CrtSetDbgFlag, Heap State Reporting Functions


_CrtDumpMemoryLeaks

Dumps all of the memory blocks in the debug heap when a memory leak has occurred (debug version only).

int _CrtDumpMemoryLeaks( void );

Routine | Required Header | Compatibility
_CrtDumpMemoryLeaks | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtDumpMemoryLeaks returns TRUE if a memory leak is found; otherwise, the function returns FALSE.

Remarks

The _CrtDumpMemoryLeaks function determines whether a memory leak has occurred since the start of program execution. When a leak is found, the debug header information for all of the objects in the heap is dumped in a user-readable form. When _DEBUG is not defined, calls to _CrtDumpMemoryLeaks are removed during preprocessing.

_CrtDumpMemoryLeaks is frequently called at the end of program execution to verify that all memory allocated by the application has been freed. The function can be called automatically at program termination by turning on the _CRTDBG_LEAK_CHECK_DF bit field of the _crtDbgFlag flag using the _CrtSetDbgFlag function.

_CrtDumpMemoryLeaks calls _CrtMemCheckpoint to obtain the current state of the heap and then scans the state for blocks that have not been freed. When an unfreed block is encountered, _CrtDumpMemoryLeaks calls _CrtMemDumpAllObjectsSince to dump information for all of the objects allocated in the heap from the start of program execution.

By default, internal C run-time blocks (_CRT_BLOCK) are not included in memory dump operations. The _CrtSetDbgFlag function can be used to turn on the _CRTDBG_CHECK_CRT_DF bit of _crtDbgFlag to include these blocks in the leak detection process.

For more information about heap state functions and the _CrtMemState structure, see the Heap State Reporting Functions. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*****************************************************************
 *  EXAMPLE  1                                                   *
 *  This simple program illustrates the basic debugging features *
 *  of the C runtime libraries, and the kind of debug output     *
 *  that these features generate.                                *
 *****************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

// This routine place comments at the head of a section of debug output
void OutputHeading( const char * explanation )
{
   _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}

// The following macros set and clear, respectively, given bits
// of the C runtime library debug flag, as specified by a bitmask.
#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

void main( )
{
   char *p1, *p2;
   _CrtMemState s1, s2, s3;

   // Send all reports to STDOUT
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );

   // Allocate 2 memory blocks and store a string in each
   p1 = malloc( 34 );
   strcpy( p1, "This is the p1 string (34 bytes)." );

   p2 = malloc( 34 );
   strcpy( p2, "This is the p2 string (34 bytes)." );

   OutputHeading(
      "Use _ASSERTE to check that the two strings are identical" );
   _ASSERTE( strcmp( p1, p2 ) == 0 );

   OutputHeading(
      "Use a _RPT macro to report the string contents as a warning" );
   _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );

   OutputHeading(
      "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
   _CrtMemDumpAllObjectsSince( NULL );

   free( p2 );

   OutputHeading(
      "Having freed p2, dump allocation information about p1 only" );
   _CrtMemDumpAllObjectsSince( NULL );

   // Store a memory checkpoint in the s1 memory-state structure
   _CrtMemCheckpoint( &s1 );

   // Allocate another block, pointed to by p2
   p2 = malloc( 38 );
   strcpy( p2, "This new p2 string occupies 38 bytes.");

   // Store a 2nd memory checkpoint in s2
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Dump the changes that occurred between two memory checkpoints" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   // Free p2 again and store a new memory checkpoint in s2
   free( p2 );
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Now the memory state at the two checkpoints is the same" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   strcpy( p1, "This new p1 string is over 34 bytes" );
   OutputHeading( "Free p1 after overwriting the end of the allocation" );
   free( p1 );

   // Set the debug-heap flag so that freed blocks are kept on the
   // linked list, to catch any inadvertent use of freed memory
   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );

   p1 = malloc( 10 );
   free( p1 );
   strcpy( p1, "Oops" );

   OutputHeading( "Perform a memory check after corrupting freed memory" );
   _CrtCheckMemory( );

   // Use explicit calls to _malloc_dbg to save file name and line number
   // information, and also to allocate Client type blocks for tracking
   p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
   p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
   strcpy( p1, "p1 points to a Normal allocation block" );
   strcpy( p2, "p2 points to a Client allocation block" );

   // You must use _free_dbg to free a Client block
   OutputHeading(
      "Using free( ) to free a Client block causes an assertion failure" );
   free( p1 );
   free( p2 );

   p1 = malloc( 10 );
   OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
   _CrtDumpMemoryLeaks( );

   // Set the debug-heap flag so that memory leaks are reported when
   // the process terminates. Then, exit.
   OutputHeading( "Program exits without freeing a memory block" );
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

Output

Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0

Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'

Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
 Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.

Now the memory state at the two checkpoints is the same:
**************************************************************************

Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.

Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.

Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse

Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Debug Functions


_CrtIsValidHeapPointer

Verifies that a specified pointer is in the local heap (debug version only).

int _CrtIsValidHeapPointer( const void *userData );

Routine | Required Header | Compatibility
_CrtIsValidHeapPointer | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtIsValidHeapPointer returns TRUE if the specified pointer is in the local heap; otherwise, the function returns FALSE.

Parameter

userData

Pointer to the beginning of an allocated memory block

Remarks

The _CrtIsValidHeapPointer function is used to ensure that a specific memory address is within the local heap. The “local” heap refers to the heap created and managed by a particular instance of the C run-time library. If a dynamically linked library (DLL) contains a static link to the run-time library, then it has its own instance of the run-time heap, and therefore its own heap, independent of the application’s local heap. When _DEBUG is not defined, calls to _CrtIsValidHeapPointer are removed during preprocessing.

Because this function returns TRUE or FALSE, it can be passed to one of the _ASSERT macros to create a simple debugging error handling mechanism. The following example will cause an assertion failure if the specified address is not located within the local heap:

_ASSERTE( _CrtIsValidHeapPointer( userData ) );

For more information about how _CrtIsValidHeapPointer can be used with other debug functions and macros, see Using Macros for Verification and Reporting. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*
 * ISVALID.C
 * This program allocates a block of memory using _malloc_dbg
 * and then tests the validity of this memory by calling _CrtIsMemoryBlock,
 * _CrtIsValidPointer, and _CrtIsValidHeapPointer.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

#define  TRUE   1
#define  FALSE  0

void main( void )
{
        char *my_pointer;

        /*
         * Call _malloc_dbg to include the filename and line number
         * of our allocation request in the header information
         */
        my_pointer = (char *)_malloc_dbg( sizeof(char) * 10, _NORMAL_BLOCK, __FILE__, __LINE__ );

        /*
         * Ensure that the memory got allocated correctly
         */
        _CrtIsMemoryBlock((const void *)my_pointer, sizeof(char) * 10, NULL, NULL, NULL );

        /*
         * Test for read/write accessibility
         */
        if (_CrtIsValidPointer((const void *)my_pointer, sizeof(char) * 10, TRUE))
                printf("my_pointer has read and write accessibility.\n");
        else
                printf("my_pointer only has read access.\n");

        /*
         * Make sure my_pointer is within the local heap
         */
        if (_CrtIsValidHeapPointer((const void *)my_pointer))
                printf("my_pointer is within the local heap.\n");
        else
                printf("my_pointer is not located within the local heap.\n");

        free(my_pointer);
}

Output

my_pointer has read and write accessibility.
my_pointer is within the local heap.

Debug Functions


_CrtIsMemoryBlock

Verifies that a specified memory block is in the local heap and that it has a valid debug heap block type identifier (debug version only).

int _CrtIsMemoryBlock( const void *userData, unsigned int size, long *requestNumber, char **filename, int *linenumber );

Routine | Required Header | Compatibility
_CrtIsMemoryBlock | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtIsMemoryBlock returns TRUE if the specified memory block is located within the local heap and has a valid debug heap block type identifier; otherwise, the function returns FALSE.

Parameter

userData

Pointer to the beginning of the memory block to verify

size

Size of the specified block (bytes)

requestNumber

Pointer to the allocation number of the block or NULL

filename

Pointer to name of source file that requested the block or NULL

linenumber

Pointer to the line number in the source file or NULL

Remarks

The _CrtIsMemoryBlock function verifies that a specified memory block is located within the application’s local heap and that it has a valid block type identifier. This function can also be used to obtain the object allocation order number and source file name/line number where the memory block allocation was originally requested. Passing non-NULL values for the requestNumber, filename, and/or linenumber parameters causes _CrtIsMemoryBlock to set these parameters to the values in the memory block’s debug header, if it finds the block in the local heap. When _DEBUG is not defined, calls to _CrtIsMemoryBlock are removed during preprocessing.

Because this function returns TRUE or FALSE, it can be passed to one of the _ASSERT macros to create a simple debugging error handling mechanism. The following example will cause an assertion failure if the specified address is not located within the local heap:

_ASSERTE( _CrtIsMemoryBlock( userData, size, &requestNumber, &filename, &linenumber ) );

For more information about how _CrtIsMemoryBlock can be used with other debug functions and macros, see Using Macros for Verification and Reporting. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*
 * ISVALID.C
 * This program allocates a block of memory using _malloc_dbg
 * and then tests the validity of this memory by calling _CrtIsMemoryBlock,
 * _CrtIsValidPointer, and _CrtIsValidHeapPointer.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

#define  TRUE   1
#define  FALSE  0

void main( void )
{
        char *my_pointer;

        /*
         * Call _malloc_dbg to include the filename and line number
         * of our allocation request in the header information
         */
        my_pointer = (char *)_malloc_dbg( sizeof(char) * 10, _NORMAL_BLOCK, __FILE__, __LINE__ );

        /*
         * Ensure that the memory got allocated correctly
         */
        _CrtIsMemoryBlock((const void *)my_pointer, sizeof(char) * 10, NULL, NULL, NULL );

        /*
         * Test for read/write accessibility
         */
        if (_CrtIsValidPointer((const void *)my_pointer, sizeof(char) * 10, TRUE))
                printf("my_pointer has read and write accessibility.\n");
        else
                printf("my_pointer only has read access.\n");

        /*
         * Make sure my_pointer is within the local heap
         */
        if (_CrtIsValidHeapPointer((const void *)my_pointer))
                printf("my_pointer is within the local heap.\n");
        else
                printf("my_pointer is not located within the local heap.\n");

        free(my_pointer);
}

Output

my_pointer has read and write accessibility.
my_pointer is within the local heap.

Debug Functions


_CrtIsValidPointer

Verifies that a specified memory range is valid for reading and writing (debug version only).

int _CrtIsValidPointer( const void *address, unsigned int size, int access );

Routine | Required Header | Compatibility
_CrtIsValidPointer | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtIsValidPointer returns TRUE if the specified memory range is valid for the specified operation(s); otherwise, the function returns FALSE.

Parameter

address

Points to the beginning of the memory range to test for validity

size

Size of the specified memory range (bytes)

access

Read/Write accessibility to determine for the memory range

Remarks

The _CrtIsValidPointer function verifies that the memory range beginning at address and extending for size bytes, is valid for the specified accessibility operation(s). When access is set to TRUE, the memory range is verified for both reading and writing. When address is FALSE, the memory range is only validated for reading. When _DEBUG is not defined, calls to _CrtIsValidPointer are removed during preprocessing.

Because this function returns TRUE or FALSE, it can be passed to one of the _ASSERT macros to create a simple debugging error handling mechanism. The following example will cause an assertion failure if the memory range is not valid for both reading and writing operations:

_ASSERTE( _CrtIsValidPointer( address, size, TRUE ) );

For more information about how _CrtIsValidPointer can be used with other debug functions and macros, see Using Macros for Verification and Reporting. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*
 * ISVALID.C
 * This program allocates a block of memory using _malloc_dbg
 * and then tests the validity of this memory by calling _CrtIsMemoryBlock,
 * _CrtIsValidPointer, and _CrtIsValidHeapPointer.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

#define  TRUE   1
#define  FALSE  0

void main( void )
{
        char *my_pointer;

        /*
         * Call _malloc_dbg to include the filename and line number
         * of our allocation request in the header information
         */
        my_pointer = (char *)_malloc_dbg( sizeof(char) * 10, _NORMAL_BLOCK, __FILE__, __LINE__ );

        /*
         * Ensure that the memory got allocated correctly
         */
        _CrtIsMemoryBlock((const void *)my_pointer, sizeof(char) * 10, NULL, NULL, NULL );

        /*
         * Test for read/write accessibility
         */
        if (_CrtIsValidPointer((const void *)my_pointer, sizeof(char) * 10, TRUE))
                printf("my_pointer has read and write accessibility.\n");
        else
                printf("my_pointer only has read access.\n");

        /*
         * Make sure my_pointer is within the local heap
         */
        if (_CrtIsValidHeapPointer((const void *)my_pointer))
                printf("my_pointer is within the local heap.\n");
        else
                printf("my_pointer is not located within the local heap.\n");

        free(my_pointer);
}

Output

my_pointer has read and write accessibility.
my_pointer is within the local heap.

Debug Functions


_CrtMemCheckpoint

Obtains the current state of the debug heap and stores in an application-supplied _CrtMemState structure (debug version only).

void _CrtMemCheckpoint( _CrtMemState *state );

Routine | Required Header | Compatibility
_CrtMemCheckpoint | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

None

Parameter

state

Pointer to _CrtMemState structure to fill with the memory checkpoint

Remarks

The _CrtMemCheckpoint function creates a snapshot of the current state of the debug heap at any given moment, which can be used by other heap state functions to help detect memory leaks and other problems. When _DEBUG is not defined, calls to _CrtMemState are removed during preprocessing.

The application must pass a pointer to a previously allocated instance of the _CrtMemState structure, defined in CRTDBG.H, in the state parameter. If _CrtMemCheckpoint encounters an error during the checkpoint creation, the function generates a _CRT_WARN debug report describing the problem.

For more information about heap state functions and the _CrtMemState structure, see Heap State Reporting Functions. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*****************************************************************
 *  EXAMPLE  1                                                   *
 *  This simple program illustrates the basic debugging features *
 *  of the C runtime libraries, and the kind of debug output     *
 *  that these features generate.                                *
 *****************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

// This routine place comments at the head of a section of debug output
void OutputHeading( const char * explanation )
{
   _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}

// The following macros set and clear, respectively, given bits
// of the C runtime library debug flag, as specified by a bitmask.
#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

void main( )
{
   char *p1, *p2;
   _CrtMemState s1, s2, s3;

   // Send all reports to STDOUT
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );

   // Allocate 2 memory blocks and store a string in each
   p1 = malloc( 34 );
   strcpy( p1, "This is the p1 string (34 bytes)." );

   p2 = malloc( 34 );
   strcpy( p2, "This is the p2 string (34 bytes)." );

   OutputHeading(
      "Use _ASSERTE to check that the two strings are identical" );
   _ASSERTE( strcmp( p1, p2 ) == 0 );

   OutputHeading(
      "Use a _RPT macro to report the string contents as a warning" );
   _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );

   OutputHeading(
      "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
   _CrtMemDumpAllObjectsSince( NULL );

   free( p2 );

   OutputHeading(
      "Having freed p2, dump allocation information about p1 only" );
   _CrtMemDumpAllObjectsSince( NULL );

   // Store a memory checkpoint in the s1 memory-state structure
   _CrtMemCheckpoint( &s1 );

   // Allocate another block, pointed to by p2
   p2 = malloc( 38 );
   strcpy( p2, "This new p2 string occupies 38 bytes.");

   // Store a 2nd memory checkpoint in s2
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Dump the changes that occurred between two memory checkpoints" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   // Free p2 again and store a new memory checkpoint in s2
   free( p2 );
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Now the memory state at the two checkpoints is the same" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   strcpy( p1, "This new p1 string is over 34 bytes" );
   OutputHeading( "Free p1 after overwriting the end of the allocation" );
   free( p1 );

   // Set the debug-heap flag so that freed blocks are kept on the
   // linked list, to catch any inadvertent use of freed memory
   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );

   p1 = malloc( 10 );
   free( p1 );
   strcpy( p1, "Oops" );

   OutputHeading( "Perform a memory check after corrupting freed memory" );
   _CrtCheckMemory( );

   // Use explicit calls to _malloc_dbg to save file name and line number
   // information, and also to allocate Client type blocks for tracking
   p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
   p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
   strcpy( p1, "p1 points to a Normal allocation block" );
   strcpy( p2, "p2 points to a Client allocation block" );

   // You must use _free_dbg to free a Client block
   OutputHeading(
      "Using free( ) to free a Client block causes an assertion failure" );
   free( p1 );
   free( p2 );

   p1 = malloc( 10 );
   OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
   _CrtDumpMemoryLeaks( );

   // Set the debug-heap flag so that memory leaks are reported when
   // the process terminates. Then, exit.
   OutputHeading( "Program exits without freeing a memory block" );
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

Output

Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0

Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'

Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
 Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.

Now the memory state at the two checkpoints is the same:
**************************************************************************

Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.

Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.

Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse

Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Debug Functions


_CrtMemDifference

Compares two memory states and returns their differences (debug version only).

int _CrtMemDifference( _CrtMemState *stateDiff, const _CrtMemState *oldState, const _CrtMemState *newState );

Routine | Required Header | Compatibility
_CrtMemDifference | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

If the memory states are significantly different, _CrtMemDifference returns TRUE; otherwise, the function returns FALSE.

Parameters

stateDiff

Pointer to a _CrtMemState structure that will be used to store the differences between the two memory states (returned)

oldState

Pointer to an earlier memory state (_CrtMemState structure)

newState

Pointer to a later memory state (_CrtMemState structure)

Remarks

The _CrtMemDifference function compares oldState and newState and stores their differences in stateDiff, which can then be used by the application to detect memory leaks and other memory problems. When _DEBUG is not defined, calls to _CrtMemDifference are removed during preprocessing.

newState and oldState must each be a valid pointer to a _CrtMemState structure, defined in CRTDBG.H, that has been filled in by _CrtMemCheckpoint before calling _CrtMemDifference. stateDiff must be a pointer to a previously allocated instance of the _CrtMemState structure.

_CrtMemDifference compares the _CrtMemState field values of the blocks in oldState to those in newState and stores the result in stateDiff. When the number of allocated block types or total number of allocated blocks for each type differs between the two memory states, the states are said to be significantly different. The difference between the two states’ high water count and total allocations is also stored in stateDiff.

By default, internal C run-time blocks (_CRT_BLOCK) are not included in memory state operations. The _CrtSetDbgFlag function can be used to turn on the _CRTDBG_CHECK_CRT_DF bit of _crtDbgFlag to include these blocks in leak detection and other memory state operations. Freed memory blocks (_FREE_BLOCK) do not cause _CrtMemDifference to return TRUE.

For more information about heap state functions and the _CrtMemState structure, see Heap State Reporting Functions. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*****************************************************************
 *  EXAMPLE  1                                                   *
 *  This simple program illustrates the basic debugging features *
 *  of the C runtime libraries, and the kind of debug output     *
 *  that these features generate.                                *
 *****************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

// This routine place comments at the head of a section of debug output
void OutputHeading( const char * explanation )
{
   _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}

// The following macros set and clear, respectively, given bits
// of the C runtime library debug flag, as specified by a bitmask.
#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

void main( )
{
   char *p1, *p2;
   _CrtMemState s1, s2, s3;

   // Send all reports to STDOUT
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );

   // Allocate 2 memory blocks and store a string in each
   p1 = malloc( 34 );
   strcpy( p1, "This is the p1 string (34 bytes)." );

   p2 = malloc( 34 );
   strcpy( p2, "This is the p2 string (34 bytes)." );

   OutputHeading(
      "Use _ASSERTE to check that the two strings are identical" );
   _ASSERTE( strcmp( p1, p2 ) == 0 );

   OutputHeading(
      "Use a _RPT macro to report the string contents as a warning" );
   _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );

   OutputHeading(
      "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
   _CrtMemDumpAllObjectsSince( NULL );

   free( p2 );

   OutputHeading(
      "Having freed p2, dump allocation information about p1 only" );
   _CrtMemDumpAllObjectsSince( NULL );

   // Store a memory checkpoint in the s1 memory-state structure
   _CrtMemCheckpoint( &s1 );

   // Allocate another block, pointed to by p2
   p2 = malloc( 38 );
   strcpy( p2, "This new p2 string occupies 38 bytes.");

   // Store a 2nd memory checkpoint in s2
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Dump the changes that occurred between two memory checkpoints" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   // Free p2 again and store a new memory checkpoint in s2
   free( p2 );
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Now the memory state at the two checkpoints is the same" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   strcpy( p1, "This new p1 string is over 34 bytes" );
   OutputHeading( "Free p1 after overwriting the end of the allocation" );
   free( p1 );

   // Set the debug-heap flag so that freed blocks are kept on the
   // linked list, to catch any inadvertent use of freed memory
   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );

   p1 = malloc( 10 );
   free( p1 );
   strcpy( p1, "Oops" );

   OutputHeading( "Perform a memory check after corrupting freed memory" );
   _CrtCheckMemory( );

   // Use explicit calls to _malloc_dbg to save file name and line number
   // information, and also to allocate Client type blocks for tracking
   p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
   p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
   strcpy( p1, "p1 points to a Normal allocation block" );
   strcpy( p2, "p2 points to a Client allocation block" );

   // You must use _free_dbg to free a Client block
   OutputHeading(
      "Using free( ) to free a Client block causes an assertion failure" );
   free( p1 );
   free( p2 );

   p1 = malloc( 10 );
   OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
   _CrtDumpMemoryLeaks( );

   // Set the debug-heap flag so that memory leaks are reported when
   // the process terminates. Then, exit.
   OutputHeading( "Program exits without freeing a memory block" );
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

Output

Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0

Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'

Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
 Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.

Now the memory state at the two checkpoints is the same:
**************************************************************************

Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.

Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.

Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse

Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Debug Functions

See Also _crtDbgFlag


_CrtMemDumpAllObjectsSince

Dumps information about objects in the heap from the start of program execution or from a specified heap state (debug version only).

void _CrtMemDumpAllObjectsSince( const _CrtMemState *state );

Routine | Required Header | Compatibility
_CrtMemDumpAll- ObjectsSince | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

None

Parameter

state

Pointer to the heap state to begin dumping from or NULL

Remarks

The _CrtMemDumpAllObjectsSince function dumps the debug header information of objects allocated in the heap in a user-readable form. The dump information can be used by the application to track allocations and detect memory problems. When _DEBUG is not defined, calls to _CrtMemDumpAllObjectsSince are removed during preprocessing.

_CrtMemDumpAllObjectsSince uses the value of the state parameter to determine where to initiate the dump operation. To begin dumping from a specified heap state, the state parameter must be a pointer to a _CrtMemState structure that has been filled in by _CrtMemCheckpoint before _CrtMemDumpAllObjectsSince was called. When state is NULL, the function begins the dump from the start of program execution.

If the application has installed a dump hook function by calling _CrtSetDumpClient, then every time _CrtMemDumpAllObjectsSince dumps information about a _CLIENT_BLOCK type of block, it calls the application-supplied dump function as well. By default, internal C run-time blocks (_CRT_BLOCK) are not included in memory dump operations. The _CrtSetDbgFlag function can be used to turn on the _CRTDBG_CHECK_CRT_DF bit of _crtDbgFlag to include these blocks. In addition, blocks marked as freed or ignored (_FREE_BLOCK, _IGNORE_BLOCK) are not included in the memory dump.

For more information about heap state functions and the _CrtMemState structure, see Heap State Reporting Functions. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*****************************************************************
 *  EXAMPLE  2                                                   *
 *  ----------                                                   *
 *  This program illustrates several ways to use debugging hook  *
 *  functions with the new debug versions of the C runtime       *
 *  libraries. To add some realism, it has a few elements of an  *
 *  actual application, including two bugs.                      *
 *                                                               *
 *  The program stores birthdate information in a linked list    *
 *  of Client blocks. A Client-dump hook function validates the  *
 *  birthday data and reports the contents of the Client blocks. *
 *  An allocation hook function logs heap operations to a text   *
 *  file, and the report hook function logs reports to the same  *
 *  text file.                                                   *
 *                                                               *
 *  NOTE: The allocation hook function explicitly excludes CRT   *
 *        blocks (the memory allocated internally by the C       *
 *        runtime library) from its log. It is important to      *
 *        understand why! The hook function uses fprintf( ) to   *
 *        write to the log file, and fprintf( ) allocates a CRT  *
 *        block. If CRT blocks were not excluded in this case,   *
 *        an endless loop would be created in which fprintf( )   *
 *        would cause the hook function to be called, and the    *
 *        hook would in turn call fprintf( ), which would cause  *
 *        the hook to be called again, and so on. The moral is:  *
 *                                                               *
 *   -->  IF YOUR ALLOCATION HOOK USES ANY C RUNTIME FUNCTION    *
 *        THAT ALLOCATES MEMORY, THE HOOK MUST IGNORE CRT-TYPE   *
 *        ALLOCATION OPERATIONS!                                 *
 *                                                               *
 *  HINT: If you want to be able to report CRT-type blocks in    *
 *        your allocation hook, use Windows API functions for    *
 *        formatting and output, instead of C runtime functions. *
 *        Since the Windows APIs do not use the CRT heap, they   *
 *        will not trap your hook in an endless loop.            *
 *                                                               *
 *  BUGS: There are two bugs in the program below, which the     *
 *        debug heap features identify in several ways. One bug  *
 *        is that the birthDay.Name field is not large enough    *
 *        to hold several of the test names. The field should    *
 *        be larger, and strncpy( ) should be used in place of   *
 *        strcpy( ). The second bug is that the while( ) loop    *
 *        in the printRecords( ) function should not end until   *
 *        HeadPtr itself == NULL. This bug results not only in   *
 *        an incomplete display of birthdays, but also in a      *
 *        memory leak. In addition to these two bugs, Gauss'     *
 *        birthday data is out of range (April 30, not 32).      *
 *                                                               *
 *****************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <crtdbg.h>

/*****************************************************************
 *  DATA DECLARATIONS AND DEFINES                                *
 *****************************************************************/

// The following arrays provide test data for the example program:
const char * Names[] =
{
   "George Washington",
   "Thomas Jefferson",
   "Carl Friedrich Gauss",
   "Ludwig van Beethoven",
   "Thomas Carlyle"
} ;

const int Dates[] =
{
   1732,  2, 11,
   1743,  4, 13,
   1777,  4, 32,
   1795, 12,  4,
   1770, 12, 16
} ;

#define  TEST_RECS            5
// A generic sort of linked-list data structure, in this case for birthdays:
typedef struct BirthdayStruct
{
   struct BirthdayStruct * NextRec;
   int   Year;
   int   Month;
   int   Day;
   char  Name[20];
} birthDay;

birthDay * HeadPtr;
birthDay * TailPtr;

#define  FILE_IO_ERROR        0
#define  OUT_OF_MEMORY        1

#define  TRUE                 7
#define  FALSE                0

// Macros for setting or clearing bits in the CRT debug flag
#ifdef _DEBUG
#define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

/*****************************************************************
 *  SPECIAL-PURPOSE ROUTINES                                     *
 *****************************************************************/

/* ERROR HANDLER
   -------------
   Handling serious errors gracefully is a real test of craftsmanship.
   This function is just a stub; it doesn't really handle errors.
*/
void FatalError( int ErrType )
{
   exit( 1 );
}

/* MEMORY ALLOCATION FUNCTION
   --------------------------
   The createRecord function allocates memory for a new birthday record,
   fills in the structure members, and then adds the record to a linked list.
   In debug builds, it makes these allocations in Client blocks. If memory
   is not available, it calls the error handler.
*/
void createRecord(
   const int    Year,
   const int    Month,
   const int    Day,
   const char * Name
#ifdef _DEBUG
,  const unsigned char * szFileName, int nLine
#endif
   )
{
   birthDay * ptr;
   size_t n;

   n = sizeof( struct BirthdayStruct );
   ptr = (birthDay *) _malloc_dbg( n, _CLIENT_BLOCK, szFileName, nLine );
   if( ptr == NULL )
      FatalError( OUT_OF_MEMORY );
   ptr->Year = Year;
   ptr->Month = Month;
   ptr->Day = Day;
   strcpy( ptr->Name, Name );

   ptr->NextRec = NULL;
   if ( HeadPtr == NULL )     // If this is the first record in the linked list
      HeadPtr = ptr;
   else
      TailPtr->NextRec = ptr;
   TailPtr = ptr;
}

/* BIRTHDAY DISPLAY FUNCTION
   -------------------------
   This function traverses the linked list, displays the birthday data,
   and then frees the memory blocks used to store the birthdays.
*/
void printRecords( )
{
   birthDay * ptr;
   char *months[] = {
      "", "January", "February", "March", "April", "May", "June", "July",
      "August", "September", "October", "November", "December" };

   if ( HeadPtr == NULL )        // Do nothing if list is empty
      return;

   printf( "\n\nThis is the birthday list:\n" );
   while ( HeadPtr->NextRec != NULL )
   {
      printf( "   %s was born on %s %d, %d.\n",
              HeadPtr->Name, months[HeadPtr->Month], HeadPtr->Day, HeadPtr->Year );
      ptr = HeadPtr->NextRec;
      _free_dbg( HeadPtr, _CLIENT_BLOCK );
      HeadPtr = ptr;
   }
}

/*****************************************************************
 *  DEBUG C RUNTIME LIBRARY HOOK FUNCTIONS AND DEFINES           *
 *****************************************************************/
#ifdef _DEBUG
#define  createRecord(a, b, c, d) \
         createRecord(a, b, c, d, __FILE__, __LINE__)
FILE *logFile;                // Used to log allocation information
const char lineStr[] = { "---------------------------------------\
--------------------------------------\n"  };

/* CLIENT DUMP HOOK FUNCTION
   -------------------------
   A hook function for dumping a Client block usually reports some
   or all of the contents of the block in question.  The function
   below also checks the data in several ways, and reports corruption
   or inconsistency as an assertion failure.
*/
void __cdecl MyDumpClientHook(
   void * pUserData,
   size_t nBytes
   )
{
   birthDay * bday;

   bday = (birthDay *) pUserData;

   _RPT4( _CRT_WARN, "   The birthday of %s is %d/%d/%d.\n",
          bday->Name, bday->Month, bday->Day, bday->Year );
   _ASSERTE( ( bday->Day > 0 ) && ( bday->Day < 32 ) );
   _ASSERTE( ( bday->Month > 0 ) && ( bday->Month < 13 ) );
   _ASSERTE( ( bday->Year > 0 ) && ( bday->Year < 1996 ) );
}

/* ALLOCATION HOOK FUNCTION
   -------------------------
   An allocation hook function can have many, many different
   uses. This one simply logs each allocation operation in a file.
*/
int __cdecl MyAllocHook(
   int      nAllocType,
   void   * pvData,
   size_t   nSize,
   int      nBlockUse,
   long     lRequest,
   const unsigned char * szFileName,
   int      nLine
   )
{
   char *operation[] = { "", "allocating", "re-allocating", "freeing" };
   char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };

   if ( nBlockUse == _CRT_BLOCK )   // Ignore internal C runtime library allocations
      return( TRUE );

   _ASSERT( ( nAllocType > 0 ) && ( nAllocType < 4 ) );
   _ASSERT( ( nBlockUse >= 0 ) && ( nBlockUse < 5 ) );

   fprintf( logFile,
            "Memory operation in %s, line %d: %s a %d-byte '%s' block (# %ld)\n",
            szFileName, nLine, operation[nAllocType], nSize,
            blockType[nBlockUse], lRequest );
   if ( pvData != NULL )
      fprintf( logFile, " at %X", pvData );

   return( TRUE );         // Allow the memory operation to proceed
}

/* REPORT HOOK FUNCTION
   --------------------
   Again, report hook functions can serve a very wide variety of purposes.
   This one logs error and assertion failure debug reports in the
   log file, along with 'Damage' reports about overwritten memory.

   By setting the retVal parameter to zero, we are instructing _CrtDbgReport
   to return zero, which causes execution to continue. If we want the function
   to start the debugger, we should have _CrtDbgReport return one.
*/
int MyReportHook(
   int   nRptType,
   char *szMsg,
   int  *retVal
   )
{
   char *RptTypes[] = { "Warning", "Error", "Assert" };

   if ( ( nRptType > 0 ) || ( strstr( szMsg, "DAMAGE" ) ) )
      fprintf( logFile, "%s: %s", RptTypes[nRptType], szMsg );

   retVal = 0;

   return( TRUE );         // Allow the report to be made as usual

}
#endif                     // End of #ifdef _DEBUG

/*****************************************************************
 *  MAIN FUNCTION                                                *
 *****************************************************************/
void main( )
{
   int i, j;

#ifdef _DEBUG
   _CrtMemState checkPt1;
   char timeStr[10], dateStr[10];         // Used to set up log file

   // Send all reports to STDOUT, since this example is a console app
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   // Set the debug heap to report memory leaks when the process terminates,
   // and to keep freed blocks in the linked list.
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF );

   // Open a log file for the hook functions to use
   logFile = fopen( "MEM-LOG.TXT", "w" );
   if ( logFile == NULL )
      FatalError( FILE_IO_ERROR );
   _strtime( timeStr );
   _strdate( dateStr );
   fprintf( logFile,
            "Memory Allocation Log File for Example Program, run at %s on %s.\n",
            timeStr, dateStr );
   fputs( lineStr, logFile );

   // Install the hook functions
   _CrtSetDumpClient( MyDumpClientHook );
   _CrtSetAllocHook( MyAllocHook );
   _CrtSetReportHook( MyReportHook );

#endif                     // End of #ifdef _DEBUG

   HeadPtr = NULL;

   // Create a trial birthday record.
   createRecord( 1749, 3, 23, "Pierre de Laplace" );

   // Check the debug heap, and dump the new birthday record. --Note that
   // debug C runtime library functions such as _CrtCheckMemory( ) and
   // _CrtMemDumpAllObjectsSince( ) automatically disappear in a release build.
   _CrtMemDumpAllObjectsSince( NULL );
   _CrtCheckMemory( );
   _CrtMemCheckpoint( &checkPt1 );

   // Since everything has worked so far, create more records
   for ( i = 0, j = 0; i < TEST_RECS; i++, j+=3 )
      createRecord( Dates[j], Dates[j+1], Dates[j+2], Names[i] );

   // Examine the results
   _CrtMemDumpAllObjectsSince( &checkPt1 );
   _CrtMemCheckpoint( &checkPt1 );
   _CrtMemDumpStatistics( &checkPt1 );
   _CrtCheckMemory( );

   // This fflush needs to be removed...
   fflush( logFile );

   // Now try displaying the records, which frees the memory being used
   printRecords( );

   // OK, time to go. Did I forget to turn out any lights? I could check
   // explicitly using _CrtDumpMemoryLeaks( ), but I have set
   // _CRTDBG_LEAK_CHECK_DF, so the C runtime library debug heap will
   // automatically alert me at exit of any memory leaks.

#ifdef _DEBUG
   fclose( logFile );
#endif
}

Output

Screen output:

Dumping objects ->
C:\DEV\EXAMPLE2.C(327) : {13} client block at 0x00661B38, subtype 0, 36 bytes long:
   The birthday of Pierre de Laplace is 3/23/1749.
Object dump complete.
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
C:\DEV\EXAMPLE2.C(338) : {17} client block at 0x00661C68, subtype 0, 36 bytes long:
   The birthday of Ludwig van Beethoven is 12/4/1795.
C:\DEV\EXAMPLE2.C(338) : {16} client block at 0x00661C1C, subtype 0, 36 bytes long:
   The birthday of Carl Friedrich Gauss is 4/32/1777.
C:\DEV\EXAMPLE2.C(219) : Assertion failed: ( bday->Day > 0 ) && ( bday->Day < 32 )
C:\DEV\EXAMPLE2.C(338) : {15} client block at 0x00661BD0, subtype 0, 36 bytes long:
   The birthday of Thomas Jefferson is 4/13/1743.
C:\DEV\EXAMPLE2.C(338) : {14} client block at 0x00661B84, subtype 0, 36 bytes long:
   The birthday of George Washington is 2/11/1732.
Object dump complete.
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
6442 bytes in 12 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
216 bytes in 6 (null) Blocks.
Largest number used: 6658 bytes.
Total allocations: 6658 bytes.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C68 is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C1C is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.

This is the birthday list:
   Pierre de Laplace was born on March 23, 1749.
   George Washington was born on February 11, 1732.
   Thomas Jefferson was born on April 13, 1743.
   Carl Friedrich Gauss was born on April 32, 1777.
   Ludwig van Beethoven was born on December 4, 1795.
Detected memory leaks!
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
Object dump complete.

Log file output:

Memory Allocation Log File for Example Program, run at 14:11:01 on 04/28/95.
-----------------------------------------------------------------------------
Memory operation in C:\DEV\EXAMPLE2.C, line 327:
                                   allocating a 36-byte 'Client' block (# 13)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 14)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 15)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 16)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 17)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 18)
Assert: C:\DEV\EXAMPLE2.C(219) : Assertion failed:
                                    ( bday->Day > 0 ) && ( bday->Day < 32 )
Warning: DAMAGE: after (null) block (#17) at 0x00661C68.
Warning: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661B38Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661B84Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661BD0Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661C1CError: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661C68Error: DAMAGE: after (null) block (#17) at 0x00661C68.

Debug Functions

See Also _crtDbgFlag


_CrtMemDumpStatistics

Dumps the debug header information for a specified heap state in a user-readable form (debug version only).

void _CrtMemDumpStatistics( const _CrtMemState *state );

Routine | Required Header | Compatibility
_CrtMemDumpStatistics | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

None

Parameter

state

Pointer to the heap state to dump

Remarks

The _CrtMemDumpStatistics function dumps the debug header information for a specified state of the heap in a user-readable form. The dump statistics can be used by the application to track allocations and detect memory problems. The memory state may contain a specific heap state, or the difference between two states. When _DEBUG is not defined, calls to _CrtMemDumpStatistics are removed during preprocessing.

The state parameter must be a pointer to a _CrtMemState structure that has been filled in by _CrtMemCheckpoint or returned by _CrtMemDifference before _CrtMemDumpStatistics is called.

For more information about heap state functions and the _CrtMemState structure, see Heap State Reporting Functions. For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap.

Example

/*****************************************************************
 *  EXAMPLE  1                                                   *
 *  This simple program illustrates the basic debugging features *
 *  of the C runtime libraries, and the kind of debug output     *
 *  that these features generate.                                *
 *****************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

// This routine place comments at the head of a section of debug output
void OutputHeading( const char * explanation )
{
   _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}

// The following macros set and clear, respectively, given bits
// of the C runtime library debug flag, as specified by a bitmask.
#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

void main( )
{
   char *p1, *p2;
   _CrtMemState s1, s2, s3;

   // Send all reports to STDOUT
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );

   // Allocate 2 memory blocks and store a string in each
   p1 = malloc( 34 );
   strcpy( p1, "This is the p1 string (34 bytes)." );

   p2 = malloc( 34 );
   strcpy( p2, "This is the p2 string (34 bytes)." );

   OutputHeading(
      "Use _ASSERTE to check that the two strings are identical" );
   _ASSERTE( strcmp( p1, p2 ) == 0 );

   OutputHeading(
      "Use a _RPT macro to report the string contents as a warning" );
   _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );

   OutputHeading(
      "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
   _CrtMemDumpAllObjectsSince( NULL );

   free( p2 );

   OutputHeading(
      "Having freed p2, dump allocation information about p1 only" );
   _CrtMemDumpAllObjectsSince( NULL );

   // Store a memory checkpoint in the s1 memory-state structure
   _CrtMemCheckpoint( &s1 );

   // Allocate another block, pointed to by p2
   p2 = malloc( 38 );
   strcpy( p2, "This new p2 string occupies 38 bytes.");

   // Store a 2nd memory checkpoint in s2
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Dump the changes that occurred between two memory checkpoints" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   // Free p2 again and store a new memory checkpoint in s2
   free( p2 );
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Now the memory state at the two checkpoints is the same" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   strcpy( p1, "This new p1 string is over 34 bytes" );
   OutputHeading( "Free p1 after overwriting the end of the allocation" );
   free( p1 );

   // Set the debug-heap flag so that freed blocks are kept on the
   // linked list, to catch any inadvertent use of freed memory
   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );

   p1 = malloc( 10 );
   free( p1 );
   strcpy( p1, "Oops" );

   OutputHeading( "Perform a memory check after corrupting freed memory" );
   _CrtCheckMemory( );

   // Use explicit calls to _malloc_dbg to save file name and line number
   // information, and also to allocate Client type blocks for tracking
   p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
   p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
   strcpy( p1, "p1 points to a Normal allocation block" );
   strcpy( p2, "p2 points to a Client allocation block" );

   // You must use _free_dbg to free a Client block
   OutputHeading(
      "Using free( ) to free a Client block causes an assertion failure" );
   free( p1 );
   free( p2 );

   p1 = malloc( 10 );
   OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
   _CrtDumpMemoryLeaks( );

   // Set the debug-heap flag so that memory leaks are reported when
   // the process terminates. Then, exit.
   OutputHeading( "Program exits without freeing a memory block" );
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

Output

Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0

Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'

Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
 Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.

Now the memory state at the two checkpoints is the same:
**************************************************************************

Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.

Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.

Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse

Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Debug Functions


_CrtSetAllocHook

Installs a client-defined allocation function by hooking it into the C run-time debug memory allocation process (debug version only).

_CRT_ALLOC_HOOK _CrtSetAllocHook( _CRT_ALLOC_HOOK allocHook );

Routine | Required Header | Compatibility
_CrtSetAllocHook | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtSetAllocHook returns the previously defined allocation hook function.

Parameter

allocHook

New client-defined allocation function to hook into the C run-time debug memory allocation process

Remarks

_CrtSetAllocHook allows an application to hook its own allocation function into the C run-time debug library memory allocation process. As a result, every call to a debug allocation function to allocate, reallocate, or free a memory block triggers a call to the application’s hook function. _CrtSetAllocHook provides an application with an easy method for testing how the application handles insufficient memory situations, the ability to examine allocation patterns, and the opportunity to log allocation information for later analysis. When _DEBUG is not defined, calls to _CrtSetAllocHook are removed during preprocessing.

The _CrtSetAllocHook function installs the new client-defined allocation function specified in allocHook and returns the previously defined hook function. The following example demonstrates how a client-defined allocation hook should be prototyped:

int YourAllocHook( int allocType, void *userData, size_t size, int blockType,
   long requestNumber, const unsigned char *filename, int lineNumber);

The allocType argument specifies the type of allocation operation (_HOOK_ALLOC, _HOOK_REALLOC, _HOOK_FREE) that triggered the call to the allocation’s hook function. When the triggering allocation type is _HOOK_FREE, userData is a pointer to the user data section of the memory block about to be freed. However, when the triggering allocation type is _HOOK_ALLOC or _HOOK_REALLOC, userData is NULL because the memory block has not been allocated yet.

size specifies the size of the memory block in bytes, blockType indicates the type of the memory block, requestNumber is the object allocation order number of the memory block, and if available, filename and lineNumber specify the source file name and line number where the triggering allocation operation was initiated.

After the hook function has finished processing, it must return a Boolean value, which tells the main C run-time allocation process how to continue. When the hook function wants the main allocation process to continue as if the hook function had never been called, then the hook function should return TRUE. This causes the original triggering allocation operation to be executed. Using this implementation, the hook function can gather and save allocation information for later analysis, without interfering with the current allocation operation or state of the debug heap.

When the hook function wants the main allocation process to continue as if the triggering allocation operation was called and it failed, then the hook function should return FALSE. Using this implementation, the hook function can simulate a wide range of memory conditions and debug heap states to test how the application handles each situation.

For more information about how _CrtSetAllocHook can be used with other memory management functions or how to write your own client-defined hook functions, see Writing Your Own Debugging Hook Functions.

Example

/*****************************************************************
 *  EXAMPLE  2                                                   *
 *  ----------                                                   *
 *  This program illustrates several ways to use debugging hook  *
 *  functions with the new debug versions of the C runtime       *
 *  libraries. To add some realism, it has a few elements of an  *
 *  actual application, including two bugs.                      *
 *                                                               *
 *  The program stores birthdate information in a linked list    *
 *  of Client blocks. A Client-dump hook function validates the  *
 *  birthday data and reports the contents of the Client blocks. *
 *  An allocation hook function logs heap operations to a text   *
 *  file, and the report hook function logs reports to the same  *
 *  text file.                                                   *
 *                                                               *
 *  NOTE: The allocation hook function explicitly excludes CRT   *
 *        blocks (the memory allocated internally by the C       *
 *        runtime library) from its log. It is important to      *
 *        understand why! The hook function uses fprintf( ) to   *
 *        write to the log file, and fprintf( ) allocates a CRT  *
 *        block. If CRT blocks were not excluded in this case,   *
 *        an endless loop would be created in which fprintf( )   *
 *        would cause the hook function to be called, and the    *
 *        hook would in turn call fprintf( ), which would cause  *
 *        the hook to be called again, and so on. The moral is:  *
 *                                                               *
 *   -->  IF YOUR ALLOCATION HOOK USES ANY C RUNTIME FUNCTION    *
 *        THAT ALLOCATES MEMORY, THE HOOK MUST IGNORE CRT-TYPE   *
 *        ALLOCATION OPERATIONS!                                 *
 *                                                               *
 *  HINT: If you want to be able to report CRT-type blocks in    *
 *        your allocation hook, use Windows API functions for    *
 *        formatting and output, instead of C runtime functions. *
 *        Since the Windows APIs do not use the CRT heap, they   *
 *        will not trap your hook in an endless loop.            *
 *                                                               *
 *  BUGS: There are two bugs in the program below, which the     *
 *        debug heap features identify in several ways. One bug  *
 *        is that the birthDay.Name field is not large enough    *
 *        to hold several of the test names. The field should    *
 *        be larger, and strncpy( ) should be used in place of   *
 *        strcpy( ). The second bug is that the while( ) loop    *
 *        in the printRecords( ) function should not end until   *
 *        HeadPtr itself == NULL. This bug results not only in   *
 *        an incomplete display of birthdays, but also in a      *
 *        memory leak. In addition to these two bugs, Gauss'     *
 *        birthday data is out of range (April 30, not 32).      *
 *                                                               *
 *****************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <crtdbg.h>

/*****************************************************************
 *  DATA DECLARATIONS AND DEFINES                                *
 *****************************************************************/

// The following arrays provide test data for the example program:
const char * Names[] =
{
   "George Washington",
   "Thomas Jefferson",
   "Carl Friedrich Gauss",
   "Ludwig van Beethoven",
   "Thomas Carlyle"
} ;

const int Dates[] =
{
   1732,  2, 11,
   1743,  4, 13,
   1777,  4, 32,
   1795, 12,  4,
   1770, 12, 16
} ;

#define  TEST_RECS            5
// A generic sort of linked-list data structure, in this case for birthdays:
typedef struct BirthdayStruct
{
   struct BirthdayStruct * NextRec;
   int   Year;
   int   Month;
   int   Day;
   char  Name[20];
} birthDay;

birthDay * HeadPtr;
birthDay * TailPtr;

#define  FILE_IO_ERROR        0
#define  OUT_OF_MEMORY        1

#define  TRUE                 7
#define  FALSE                0

// Macros for setting or clearing bits in the CRT debug flag
#ifdef _DEBUG
#define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

/*****************************************************************
 *  SPECIAL-PURPOSE ROUTINES                                     *
 *****************************************************************/

/* ERROR HANDLER
   -------------
   Handling serious errors gracefully is a real test of craftsmanship.
   This function is just a stub; it doesn't really handle errors.
*/
void FatalError( int ErrType )
{
   exit( 1 );
}

/* MEMORY ALLOCATION FUNCTION
   --------------------------
   The createRecord function allocates memory for a new birthday record,
   fills in the structure members, and then adds the record to a linked list.
   In debug builds, it makes these allocations in Client blocks. If memory
   is not available, it calls the error handler.
*/
void createRecord(
   const int    Year,
   const int    Month,
   const int    Day,
   const char * Name
#ifdef _DEBUG
,  const unsigned char * szFileName, int nLine
#endif
   )
{
   birthDay * ptr;
   size_t n;

   n = sizeof( struct BirthdayStruct );
   ptr = (birthDay *) _malloc_dbg( n, _CLIENT_BLOCK, szFileName, nLine );
   if( ptr == NULL )
      FatalError( OUT_OF_MEMORY );
   ptr->Year = Year;
   ptr->Month = Month;
   ptr->Day = Day;
   strcpy( ptr->Name, Name );

   ptr->NextRec = NULL;
   if ( HeadPtr == NULL )     // If this is the first record in the linked list
      HeadPtr = ptr;
   else
      TailPtr->NextRec = ptr;
   TailPtr = ptr;
}

/* BIRTHDAY DISPLAY FUNCTION
   -------------------------
   This function traverses the linked list, displays the birthday data,
   and then frees the memory blocks used to store the birthdays.
*/
void printRecords( )
{
   birthDay * ptr;
   char *months[] = {
      "", "January", "February", "March", "April", "May", "June", "July",
      "August", "September", "October", "November", "December" };

   if ( HeadPtr == NULL )        // Do nothing if list is empty
      return;

   printf( "\n\nThis is the birthday list:\n" );
   while ( HeadPtr->NextRec != NULL )
   {
      printf( "   %s was born on %s %d, %d.\n",
              HeadPtr->Name, months[HeadPtr->Month], HeadPtr->Day, HeadPtr->Year );
      ptr = HeadPtr->NextRec;
      _free_dbg( HeadPtr, _CLIENT_BLOCK );
      HeadPtr = ptr;
   }
}

/*****************************************************************
 *  DEBUG C RUNTIME LIBRARY HOOK FUNCTIONS AND DEFINES           *
 *****************************************************************/
#ifdef _DEBUG
#define  createRecord(a, b, c, d) \
         createRecord(a, b, c, d, __FILE__, __LINE__)
FILE *logFile;                // Used to log allocation information
const char lineStr[] = { "---------------------------------------\
--------------------------------------\n"  };

/* CLIENT DUMP HOOK FUNCTION
   -------------------------
   A hook function for dumping a Client block usually reports some
   or all of the contents of the block in question.  The function
   below also checks the data in several ways, and reports corruption
   or inconsistency as an assertion failure.
*/
void __cdecl MyDumpClientHook(
   void * pUserData,
   size_t nBytes
   )
{
   birthDay * bday;

   bday = (birthDay *) pUserData;

   _RPT4( _CRT_WARN, "   The birthday of %s is %d/%d/%d.\n",
          bday->Name, bday->Month, bday->Day, bday->Year );
   _ASSERTE( ( bday->Day > 0 ) && ( bday->Day < 32 ) );
   _ASSERTE( ( bday->Month > 0 ) && ( bday->Month < 13 ) );
   _ASSERTE( ( bday->Year > 0 ) && ( bday->Year < 1996 ) );
}

/* ALLOCATION HOOK FUNCTION
   -------------------------
   An allocation hook function can have many, many different
   uses. This one simply logs each allocation operation in a file.
*/
int __cdecl MyAllocHook(
   int      nAllocType,
   void   * pvData,
   size_t   nSize,
   int      nBlockUse,
   long     lRequest,
   const unsigned char * szFileName,
   int      nLine
   )
{
   char *operation[] = { "", "allocating", "re-allocating", "freeing" };
   char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };

   if ( nBlockUse == _CRT_BLOCK )   // Ignore internal C runtime library allocations
      return( TRUE );

   _ASSERT( ( nAllocType > 0 ) && ( nAllocType < 4 ) );
   _ASSERT( ( nBlockUse >= 0 ) && ( nBlockUse < 5 ) );

   fprintf( logFile,
            "Memory operation in %s, line %d: %s a %d-byte '%s' block (# %ld)\n",
            szFileName, nLine, operation[nAllocType], nSize,
            blockType[nBlockUse], lRequest );
   if ( pvData != NULL )
      fprintf( logFile, " at %X", pvData );

   return( TRUE );         // Allow the memory operation to proceed
}

/* REPORT HOOK FUNCTION
   --------------------
   Again, report hook functions can serve a very wide variety of purposes.
   This one logs error and assertion failure debug reports in the
   log file, along with 'Damage' reports about overwritten memory.

   By setting the retVal parameter to zero, we are instructing _CrtDbgReport
   to return zero, which causes execution to continue. If we want the function
   to start the debugger, we should have _CrtDbgReport return one.
*/
int MyReportHook(
   int   nRptType,
   char *szMsg,
   int  *retVal
   )
{
   char *RptTypes[] = { "Warning", "Error", "Assert" };

   if ( ( nRptType > 0 ) || ( strstr( szMsg, "DAMAGE" ) ) )
      fprintf( logFile, "%s: %s", RptTypes[nRptType], szMsg );

   retVal = 0;

   return( TRUE );         // Allow the report to be made as usual

}
#endif                     // End of #ifdef _DEBUG

/*****************************************************************
 *  MAIN FUNCTION                                                *
 *****************************************************************/
void main( )
{
   int i, j;

#ifdef _DEBUG
   _CrtMemState checkPt1;
   char timeStr[10], dateStr[10];         // Used to set up log file

   // Send all reports to STDOUT, since this example is a console app
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   // Set the debug heap to report memory leaks when the process terminates,
   // and to keep freed blocks in the linked list.
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF );

   // Open a log file for the hook functions to use
   logFile = fopen( "MEM-LOG.TXT", "w" );
   if ( logFile == NULL )
      FatalError( FILE_IO_ERROR );
   _strtime( timeStr );
   _strdate( dateStr );
   fprintf( logFile,
            "Memory Allocation Log File for Example Program, run at %s on %s.\n",
            timeStr, dateStr );
   fputs( lineStr, logFile );

   // Install the hook functions
   _CrtSetDumpClient( MyDumpClientHook );
   _CrtSetAllocHook( MyAllocHook );
   _CrtSetReportHook( MyReportHook );

#endif                     // End of #ifdef _DEBUG

   HeadPtr = NULL;

   // Create a trial birthday record.
   createRecord( 1749, 3, 23, "Pierre de Laplace" );

   // Check the debug heap, and dump the new birthday record. --Note that
   // debug C runtime library functions such as _CrtCheckMemory( ) and
   // _CrtMemDumpAllObjectsSince( ) automatically disappear in a release build.
   _CrtMemDumpAllObjectsSince( NULL );
   _CrtCheckMemory( );
   _CrtMemCheckpoint( &checkPt1 );

   // Since everything has worked so far, create more records
   for ( i = 0, j = 0; i < TEST_RECS; i++, j+=3 )
      createRecord( Dates[j], Dates[j+1], Dates[j+2], Names[i] );

   // Examine the results
   _CrtMemDumpAllObjectsSince( &checkPt1 );
   _CrtMemCheckpoint( &checkPt1 );
   _CrtMemDumpStatistics( &checkPt1 );
   _CrtCheckMemory( );

   // This fflush needs to be removed...
   fflush( logFile );

   // Now try displaying the records, which frees the memory being used
   printRecords( );

   // OK, time to go. Did I forget to turn out any lights? I could check
   // explicitly using _CrtDumpMemoryLeaks( ), but I have set
   // _CRTDBG_LEAK_CHECK_DF, so the C runtime library debug heap will
   // automatically alert me at exit of any memory leaks.

#ifdef _DEBUG
   fclose( logFile );
#endif
}

Output

Screen output:

Dumping objects ->
C:\DEV\EXAMPLE2.C(327) : {13} client block at 0x00661B38, subtype 0, 36 bytes long:
   The birthday of Pierre de Laplace is 3/23/1749.
Object dump complete.
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
C:\DEV\EXAMPLE2.C(338) : {17} client block at 0x00661C68, subtype 0, 36 bytes long:
   The birthday of Ludwig van Beethoven is 12/4/1795.
C:\DEV\EXAMPLE2.C(338) : {16} client block at 0x00661C1C, subtype 0, 36 bytes long:
   The birthday of Carl Friedrich Gauss is 4/32/1777.
C:\DEV\EXAMPLE2.C(219) : Assertion failed: ( bday->Day > 0 ) && ( bday->Day < 32 )
C:\DEV\EXAMPLE2.C(338) : {15} client block at 0x00661BD0, subtype 0, 36 bytes long:
   The birthday of Thomas Jefferson is 4/13/1743.
C:\DEV\EXAMPLE2.C(338) : {14} client block at 0x00661B84, subtype 0, 36 bytes long:
   The birthday of George Washington is 2/11/1732.
Object dump complete.
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
6442 bytes in 12 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
216 bytes in 6 (null) Blocks.
Largest number used: 6658 bytes.
Total allocations: 6658 bytes.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C68 is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C1C is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.

This is the birthday list:
   Pierre de Laplace was born on March 23, 1749.
   George Washington was born on February 11, 1732.
   Thomas Jefferson was born on April 13, 1743.
   Carl Friedrich Gauss was born on April 32, 1777.
   Ludwig van Beethoven was born on December 4, 1795.
Detected memory leaks!
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
Object dump complete.

Log file output:

Memory Allocation Log File for Example Program, run at 14:11:01 on 04/28/95.
-----------------------------------------------------------------------------
Memory operation in C:\DEV\EXAMPLE2.C, line 327:
                                   allocating a 36-byte 'Client' block (# 13)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 14)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 15)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 16)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 17)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 18)
Assert: C:\DEV\EXAMPLE2.C(219) : Assertion failed:
                                    ( bday->Day > 0 ) && ( bday->Day < 32 )
Warning: DAMAGE: after (null) block (#17) at 0x00661C68.
Warning: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661B38Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661B84Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661BD0Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661C1CError: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661C68Error: DAMAGE: after (null) block (#17) at 0x00661C68.

Debug Functions


_CrtSetBreakAlloc

Sets a breakpoint on a specified object allocation order number (debug version only).

long _CrtSetBreakAlloc( long lBreakAlloc );

Routine | Required Header | Compatibility
_CrtSetBreakAlloc | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtSetBreakAlloc returns the previous object allocation order number that had a breakpoint set.

Parameter

lBreakAlloc

Allocation order number, for which to set the breakpoint

Remarks

_CrtSetBreakAlloc allows an application to perform memory leak detection by breaking at a specific point of memory allocation and tracing back to the origin of the request. The function uses the sequential object allocation order number assigned to the memory block when it was allocated in the heap. When _DEBUG is not defined, calls to _CrtSetBreakAlloc are removed during preprocessing.

The object allocation order number is stored in the lRequest field of the _CrtMemBlockHeader structure, defined in CRTDBG.H. When information about a memory block is reported by one of the debug dump functions, this number is enclosed in curly brackets; for example, {36}.

For more information about how _CrtSetBreakAlloc can be used with other memory management functions, see Tracking Heap Allocation Requests.

Example

/*
 * SETBRKAL.C
 * In this program, a call is made to the _CrtSetBreakAlloc routine
 * to verify that the debugger halts program execution when it reaches
 * a specified allocation number.
 */

#include <malloc.h>
#include <crtdbg.h>

void main( )
{
        long allocReqNum;
        char *my_pointer;

        /*
         * Allocate "my_pointer" for the first
         * time and ensure that it gets allocated correctly
         */
        my_pointer = malloc(10);
        _CrtIsMemoryBlock(my_pointer, 10, &allocReqNum, NULL, NULL);

        /*
         * Set a breakpoint on the allocation request
         * number for "my_pointer"
         */
        _CrtSetBreakAlloc(allocReqNum+2);
        _crtBreakAlloc = allocReqNum+2;

        /*
         * Alternate freeing and reallocating "my_pointer"
         * to verify that the debugger halts program execution
         * when it reaches the allocation request
         */
        free(my_pointer);
        my_pointer = malloc(10);
        free(my_pointer);
        my_pointer = malloc(10);
        free(my_pointer);
}

Output

The exception Breakpoint
A breakpoint has been reached.
(0x0000003) occurred in the application at location 0x00401255.

Debug Functions


_CrtSetDbgFlag

Retrieves and/or modifies the state of the _crtDbgFlag flag to control the allocation behavior of the debug heap manager (debug version only).

int _CrtSetDbgFlag( int newFlag );

Routine | Required Header | Compatibility
_CrtSetDbgFlag | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

_CrtSetDbgFlag returns the previous state of _crtDbgFlag.

Parameter

newFlag

New state for the _crtDbgFlag

Remarks

The _CrtSetDbgFlag function allows the application to control how the debug heap manager tracks memory allocations by modifying the bit fields of the _crtDbgFlag flag. By setting the bits (turning on), the application can instruct the debug heap manager to perform special debugging operations, including checking for memory leaks when the application exits and reporting if any are found, simulating low memory conditions by specifying that freed memory blocks should remain in the heap’s linked list, and verifying the integrity of the heap by inspecting each memory block at every allocation request. When _DEBUG is not defined, calls to _CrtSetDbgFlag are removed during preprocessing.

The following table lists the bit fields for _crtDbgFlag and describes their behavior. Because setting the bits results in increased diagnostic output and reduced program execution speed, most of the bits are not set (turned off) by default. For more information about these bit fields, see Using the Debug Heap.

Bit field | Default | Description
_CRTDBG_ALLOC- _MEM_DF | ON | ON: Enable debug heap allocations and use of memory block type identifiers, such as _CLIENT_BLOCK. OFF: Add new allocations to heap’s linked list, but set block type to _IGNORE_BLOCK.
_CRTDBG_CHECK- _ALWAYS_DF | OFF | ON: Call _CrtCheckMemory at every allocation and deallocation request. OFF: _CrtCheckMemory must be called explicitly.
_CRTDBG_CHECK- _CRT_DF | OFF | ON: Include _CRT_BLOCK types in leak detection and memory state difference operations. OFF: Memory used internally by the run-time library is ignored by these operations.
_CRTDBG_DELAY- _FREE_MEM_DF | OFF | ON: Keep freed memory blocks in the heap’s linked list, assign them the _FREE_BLOCK type, and fill them with the byte value 0xDD. OFF: Do not keep freed blocks in the heap’s linked list.
_CRTDBG_LEAK- _CHECK_DF | OFF | ON: Perform automatic leak checking at program exit via a call to _CrtDumpMemoryLeaks and generate an error report if the application failed to free all the memory it allocated. OFF: Do not automatically perform leak checking at program exit.

newFlag is the new state to apply to the _crtDbgFlag and is a combination of the values for each of the bit fields. To change one or more of these bit fields and create a new state for the flag, follow these steps:

  1. Call _CrtSetDbgFlag with newFlag equal to _CRTDBG_REPORT_FLAG to obtain the current _crtDbgFlag state and store the returned value in a temporary variable.

  2. Turn on any bits by OR-ing the temporary variable with the corresponding bitmasks (represented in the application code by manifest constants).

  3. Turn off the other bits by AND-ing the variable with a bitwise NOT of the appropriate bitmasks.

  4. Call _CrtSetDbgFlag with newFlag equal to the value stored in the temporary variable to set the new state for _crtDbgFlag.

The following lines of code demonstrate how to simulate low memory conditions by keeping freed memory blocks in the heap’s linked list and prevent _CrtCheckMemory from being called at every allocation request:

// Get the current state of the flag
// and store it in a temporary variable
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );

// Turn On (OR) - Keep freed memory blocks in the
// heap’s linked list and mark them as freed
tmpFlag |= _CRTDBG_DELAY_FREE_MEM_DF;

// Turn Off (AND) - prevent _CrtCheckMemory from
// being called at every allocation request
tmpFlag &= ~_CRTDBG_CHECK_ALWAYS_DF;

// Set the new state for the flag
_CrtSetDbgFlag( tmpFlag );

For an overview of memory management and the debug heap, see Memory Management and the Debug Heap.

To disable a flag with the _CrtSetDbgFlag function, you should AND the variable with the bitwise NOT of the bitmask.

Example

/*
 * SETDFLAG.C
 * This program concentrates on allocating and freeing memory
 * blocks to test the functionality of the _crtDbgFlag flag..
 */

#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

void main( )
{
        char *p1, *p2;
        int tmpDbgFlag;

        /*
         * Set the debug-heap flag to keep freed blocks in the
         * heap's linked list - This will allow us to catch any
         * inadvertent use of freed memory
         */
        tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
        tmpDbgFlag |= _CRTDBG_DELAY_FREE_MEM_DF;
        tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
        _CrtSetDbgFlag(tmpDbgFlag);

        /*
         * Allocate 2 memory blocks and store a string in each
         */
        p1 = malloc( 34 );
        p2 = malloc( 38 );
        strcpy( p1, "p1 points to a Normal allocation block" );
        strcpy( p2, "p2 points to a Client allocation block" );

        /*
         * Free both memory blocks
         */
        free( p2 );
        free( p1 );

        /*
         * Set the debug-heap flag to no longer keep freed blocks in the
         * heap's linked list and turn on Debug type allocations (CLIENT)
         */
        tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
        tmpDbgFlag |= _CRTDBG_ALLOC_MEM_DF;
        tmpDbgFlag &= ~_CRTDBG_DELAY_FREE_MEM_DF;
        _CrtSetDbgFlag(tmpDbgFlag);

        /*
         * Explicitly call _malloc_dbg to obtain the filename and line number
         * of our allocation request and also so we can allocate CLIENT type
         * blocks specifically for tracking
         */
        p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
        p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
        strcpy( p1, "p1 points to a Normal allocation block" );
        strcpy( p2, "p2 points to a Client allocation block" );

        /*
         * _free_dbg must be called to free the CLIENT block
         */
        _free_dbg( p2, _CLIENT_BLOCK );
        free( p1 );

        /*
         * Allocate p1 again and then exit - this will leave unfreed
         * memory on the heap
         */
        p1 = malloc( 10 );
}

Output

Debug Error!
Program: C:\code\setdflag.exe
DAMAGE: after Normal block (#31) at 0x002D06A8.
Press Retry to debug the application.

Debug Functions

See Also _crtDbgFlag, _CrtCheckMemory, Heap State Reporting Functions


_CrtSetDumpClient

Installs an application-defined function to dump _CLIENT_BLOCK type memory blocks (debug version only).

_CRT_DUMP_CLIENT _CrtSetDumpClient( _CRT_DUMP_CLIENT dumpClient );

Routine | Required Header | Compatibility
_CrtSetDumpClient | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtSetDumpClient returns the previously defined client block dump function.

Parameter

dumpClient

New client-defined memory dump function to hook into the C run-time debug memory dump process

Remarks

The _CrtSetDumpClient function allows the application to hook its own function to dump objects stored in _CLIENT_BLOCK memory blocks into the C run-time debug memory dump process. As a result, every time a debug dump function such as _CrtMemDumpAllObjectsSince or _CrtDumpMemoryLeaks dumps a _CLIENT_BLOCK memory block, the application’s dump function will be called as well. _CrtSetDumpClient provides an application with an easy method for detecting memory leaks in and validating or reporting the contents of data stored in _CLIENT_BLOCK blocks. When _DEBUG is not defined, calls to _CrtSetDumpClient are removed during preprocessing.

The _CrtSetDumpClient function installs the new application-defined dump function specified in dumpClient and returns the previously defined dump function. An example of a client block dump function is as follows:

void DumpClientFunction( void *userPortion, size_t blockSize );

The userPortion argument is a pointer to the beginning of the user data portion of the memory block and blockSize specifies the size of the allocated memory block in bytes. The client block dump function must return void. The pointer to the client dump function that is passed to _CrtSetDumpClient is of type _CRT_DUMP_CLIENT, as defined in CRTDBG.H:

typedef void (__cdecl *_CRT_DUMP_CLIENT)( void *, size_t );

For an example of how to implement an application-defined dump function, see Sample: Hook Function C Run-Time Application. For more information about functions that operate on _CLIENT_BLOCK type memory blocks, see Client Block Hook Functions.

Example

/*****************************************************************
 *  EXAMPLE  2                                                   *
 *  ----------                                                   *
 *  This program illustrates several ways to use debugging hook  *
 *  functions with the new debug versions of the C runtime       *
 *  libraries. To add some realism, it has a few elements of an  *
 *  actual application, including two bugs.                      *
 *                                                               *
 *  The program stores birthdate information in a linked list    *
 *  of Client blocks. A Client-dump hook function validates the  *
 *  birthday data and reports the contents of the Client blocks. *
 *  An allocation hook function logs heap operations to a text   *
 *  file, and the report hook function logs reports to the same  *
 *  text file.                                                   *
 *                                                               *
 *  NOTE: The allocation hook function explicitly excludes CRT   *
 *        blocks (the memory allocated internally by the C       *
 *        runtime library) from its log. It is important to      *
 *        understand why! The hook function uses fprintf( ) to   *
 *        write to the log file, and fprintf( ) allocates a CRT  *
 *        block. If CRT blocks were not excluded in this case,   *
 *        an endless loop would be created in which fprintf( )   *
 *        would cause the hook function to be called, and the    *
 *        hook would in turn call fprintf( ), which would cause  *
 *        the hook to be called again, and so on. The moral is:  *
 *                                                               *
 *   -->  IF YOUR ALLOCATION HOOK USES ANY C RUNTIME FUNCTION    *
 *        THAT ALLOCATES MEMORY, THE HOOK MUST IGNORE CRT-TYPE   *
 *        ALLOCATION OPERATIONS!                                 *
 *                                                               *
 *  HINT: If you want to be able to report CRT-type blocks in    *
 *        your allocation hook, use Windows API functions for    *
 *        formatting and output, instead of C runtime functions. *
 *        Since the Windows APIs do not use the CRT heap, they   *
 *        will not trap your hook in an endless loop.            *
 *                                                               *
 *  BUGS: There are two bugs in the program below, which the     *
 *        debug heap features identify in several ways. One bug  *
 *        is that the birthDay.Name field is not large enough    *
 *        to hold several of the test names. The field should    *
 *        be larger, and strncpy( ) should be used in place of   *
 *        strcpy( ). The second bug is that the while( ) loop    *
 *        in the printRecords( ) function should not end until   *
 *        HeadPtr itself == NULL. This bug results not only in   *
 *        an incomplete display of birthdays, but also in a      *
 *        memory leak. In addition to these two bugs, Gauss'     *
 *        birthday data is out of range (April 30, not 32).      *
 *                                                               *
 *****************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <crtdbg.h>

/*****************************************************************
 *  DATA DECLARATIONS AND DEFINES                                *
 *****************************************************************/

// The following arrays provide test data for the example program:
const char * Names[] =
{
   "George Washington",
   "Thomas Jefferson",
   "Carl Friedrich Gauss",
   "Ludwig van Beethoven",
   "Thomas Carlyle"
} ;

const int Dates[] =
{
   1732,  2, 11,
   1743,  4, 13,
   1777,  4, 32,
   1795, 12,  4,
   1770, 12, 16
} ;

#define  TEST_RECS            5
// A generic sort of linked-list data structure, in this case for birthdays:
typedef struct BirthdayStruct
{
   struct BirthdayStruct * NextRec;
   int   Year;
   int   Month;
   int   Day;
   char  Name[20];
} birthDay;

birthDay * HeadPtr;
birthDay * TailPtr;

#define  FILE_IO_ERROR        0
#define  OUT_OF_MEMORY        1

#define  TRUE                 7
#define  FALSE                0

// Macros for setting or clearing bits in the CRT debug flag
#ifdef _DEBUG
#define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

/*****************************************************************
 *  SPECIAL-PURPOSE ROUTINES                                     *
 *****************************************************************/

/* ERROR HANDLER
   -------------
   Handling serious errors gracefully is a real test of craftsmanship.
   This function is just a stub; it doesn't really handle errors.
*/
void FatalError( int ErrType )
{
   exit( 1 );
}

/* MEMORY ALLOCATION FUNCTION
   --------------------------
   The createRecord function allocates memory for a new birthday record,
   fills in the structure members, and then adds the record to a linked list.
   In debug builds, it makes these allocations in Client blocks. If memory
   is not available, it calls the error handler.
*/
void createRecord(
   const int    Year,
   const int    Month,
   const int    Day,
   const char * Name
#ifdef _DEBUG
,  const unsigned char * szFileName, int nLine
#endif
   )
{
   birthDay * ptr;
   size_t n;

   n = sizeof( struct BirthdayStruct );
   ptr = (birthDay *) _malloc_dbg( n, _CLIENT_BLOCK, szFileName, nLine );
   if( ptr == NULL )
      FatalError( OUT_OF_MEMORY );
   ptr->Year = Year;
   ptr->Month = Month;
   ptr->Day = Day;
   strcpy( ptr->Name, Name );

   ptr->NextRec = NULL;
   if ( HeadPtr == NULL )     // If this is the first record in the linked list
      HeadPtr = ptr;
   else
      TailPtr->NextRec = ptr;
   TailPtr = ptr;
}

/* BIRTHDAY DISPLAY FUNCTION
   -------------------------
   This function traverses the linked list, displays the birthday data,
   and then frees the memory blocks used to store the birthdays.
*/
void printRecords( )
{
   birthDay * ptr;
   char *months[] = {
      "", "January", "February", "March", "April", "May", "June", "July",
      "August", "September", "October", "November", "December" };

   if ( HeadPtr == NULL )        // Do nothing if list is empty
      return;

   printf( "\n\nThis is the birthday list:\n" );
   while ( HeadPtr->NextRec != NULL )
   {
      printf( "   %s was born on %s %d, %d.\n",
              HeadPtr->Name, months[HeadPtr->Month], HeadPtr->Day, HeadPtr->Year );
      ptr = HeadPtr->NextRec;
      _free_dbg( HeadPtr, _CLIENT_BLOCK );
      HeadPtr = ptr;
   }
}

/*****************************************************************
 *  DEBUG C RUNTIME LIBRARY HOOK FUNCTIONS AND DEFINES           *
 *****************************************************************/
#ifdef _DEBUG
#define  createRecord(a, b, c, d) \
         createRecord(a, b, c, d, __FILE__, __LINE__)
FILE *logFile;                // Used to log allocation information
const char lineStr[] = { "---------------------------------------\
--------------------------------------\n"  };

/* CLIENT DUMP HOOK FUNCTION
   -------------------------
   A hook function for dumping a Client block usually reports some
   or all of the contents of the block in question.  The function
   below also checks the data in several ways, and reports corruption
   or inconsistency as an assertion failure.
*/
void __cdecl MyDumpClientHook(
   void * pUserData,
   size_t nBytes
   )
{
   birthDay * bday;

   bday = (birthDay *) pUserData;

   _RPT4( _CRT_WARN, "   The birthday of %s is %d/%d/%d.\n",
          bday->Name, bday->Month, bday->Day, bday->Year );
   _ASSERTE( ( bday->Day > 0 ) && ( bday->Day < 32 ) );
   _ASSERTE( ( bday->Month > 0 ) && ( bday->Month < 13 ) );
   _ASSERTE( ( bday->Year > 0 ) && ( bday->Year < 1996 ) );
}

/* ALLOCATION HOOK FUNCTION
   -------------------------
   An allocation hook function can have many, many different
   uses. This one simply logs each allocation operation in a file.
*/
int __cdecl MyAllocHook(
   int      nAllocType,
   void   * pvData,
   size_t   nSize,
   int      nBlockUse,
   long     lRequest,
   const unsigned char * szFileName,
   int      nLine
   )
{
   char *operation[] = { "", "allocating", "re-allocating", "freeing" };
   char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };

   if ( nBlockUse == _CRT_BLOCK )   // Ignore internal C runtime library allocations
      return( TRUE );

   _ASSERT( ( nAllocType > 0 ) && ( nAllocType < 4 ) );
   _ASSERT( ( nBlockUse >= 0 ) && ( nBlockUse < 5 ) );

   fprintf( logFile,
            "Memory operation in %s, line %d: %s a %d-byte '%s' block (# %ld)\n",
            szFileName, nLine, operation[nAllocType], nSize,
            blockType[nBlockUse], lRequest );
   if ( pvData != NULL )
      fprintf( logFile, " at %X", pvData );

   return( TRUE );         // Allow the memory operation to proceed
}

/* REPORT HOOK FUNCTION
   --------------------
   Again, report hook functions can serve a very wide variety of purposes.
   This one logs error and assertion failure debug reports in the
   log file, along with 'Damage' reports about overwritten memory.

   By setting the retVal parameter to zero, we are instructing _CrtDbgReport
   to return zero, which causes execution to continue. If we want the function
   to start the debugger, we should have _CrtDbgReport return one.
*/
int MyReportHook(
   int   nRptType,
   char *szMsg,
   int  *retVal
   )
{
   char *RptTypes[] = { "Warning", "Error", "Assert" };

   if ( ( nRptType > 0 ) || ( strstr( szMsg, "DAMAGE" ) ) )
      fprintf( logFile, "%s: %s", RptTypes[nRptType], szMsg );

   retVal = 0;

   return( TRUE );         // Allow the report to be made as usual

}
#endif                     // End of #ifdef _DEBUG

/*****************************************************************
 *  MAIN FUNCTION                                                *
 *****************************************************************/
void main( )
{
   int i, j;

#ifdef _DEBUG
   _CrtMemState checkPt1;
   char timeStr[10], dateStr[10];         // Used to set up log file

   // Send all reports to STDOUT, since this example is a console app
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   // Set the debug heap to report memory leaks when the process terminates,
   // and to keep freed blocks in the linked list.
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF );

   // Open a log file for the hook functions to use
   logFile = fopen( "MEM-LOG.TXT", "w" );
   if ( logFile == NULL )
      FatalError( FILE_IO_ERROR );
   _strtime( timeStr );
   _strdate( dateStr );
   fprintf( logFile,
            "Memory Allocation Log File for Example Program, run at %s on %s.\n",
            timeStr, dateStr );
   fputs( lineStr, logFile );

   // Install the hook functions
   _CrtSetDumpClient( MyDumpClientHook );
   _CrtSetAllocHook( MyAllocHook );
   _CrtSetReportHook( MyReportHook );

#endif                     // End of #ifdef _DEBUG

   HeadPtr = NULL;

   // Create a trial birthday record.
   createRecord( 1749, 3, 23, "Pierre de Laplace" );

   // Check the debug heap, and dump the new birthday record. --Note that
   // debug C runtime library functions such as _CrtCheckMemory( ) and
   // _CrtMemDumpAllObjectsSince( ) automatically disappear in a release build.
   _CrtMemDumpAllObjectsSince( NULL );
   _CrtCheckMemory( );
   _CrtMemCheckpoint( &checkPt1 );

   // Since everything has worked so far, create more records
   for ( i = 0, j = 0; i < TEST_RECS; i++, j+=3 )
      createRecord( Dates[j], Dates[j+1], Dates[j+2], Names[i] );

   // Examine the results
   _CrtMemDumpAllObjectsSince( &checkPt1 );
   _CrtMemCheckpoint( &checkPt1 );
   _CrtMemDumpStatistics( &checkPt1 );
   _CrtCheckMemory( );

   // This fflush needs to be removed...
   fflush( logFile );

   // Now try displaying the records, which frees the memory being used
   printRecords( );

   // OK, time to go. Did I forget to turn out any lights? I could check
   // explicitly using _CrtDumpMemoryLeaks( ), but I have set
   // _CRTDBG_LEAK_CHECK_DF, so the C runtime library debug heap will
   // automatically alert me at exit of any memory leaks.

#ifdef _DEBUG
   fclose( logFile );
#endif
}

Output

Screen output:

Dumping objects ->
C:\DEV\EXAMPLE2.C(327) : {13} client block at 0x00661B38, subtype 0, 36 bytes long:
   The birthday of Pierre de Laplace is 3/23/1749.
Object dump complete.
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
C:\DEV\EXAMPLE2.C(338) : {17} client block at 0x00661C68, subtype 0, 36 bytes long:
   The birthday of Ludwig van Beethoven is 12/4/1795.
C:\DEV\EXAMPLE2.C(338) : {16} client block at 0x00661C1C, subtype 0, 36 bytes long:
   The birthday of Carl Friedrich Gauss is 4/32/1777.
C:\DEV\EXAMPLE2.C(219) : Assertion failed: ( bday->Day > 0 ) && ( bday->Day < 32 )
C:\DEV\EXAMPLE2.C(338) : {15} client block at 0x00661BD0, subtype 0, 36 bytes long:
   The birthday of Thomas Jefferson is 4/13/1743.
C:\DEV\EXAMPLE2.C(338) : {14} client block at 0x00661B84, subtype 0, 36 bytes long:
   The birthday of George Washington is 2/11/1732.
Object dump complete.
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
6442 bytes in 12 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
216 bytes in 6 (null) Blocks.
Largest number used: 6658 bytes.
Total allocations: 6658 bytes.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C68 is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C1C is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.

This is the birthday list:
   Pierre de Laplace was born on March 23, 1749.
   George Washington was born on February 11, 1732.
   Thomas Jefferson was born on April 13, 1743.
   Carl Friedrich Gauss was born on April 32, 1777.
   Ludwig van Beethoven was born on December 4, 1795.
Detected memory leaks!
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
Object dump complete.

Log file output:

Memory Allocation Log File for Example Program, run at 14:11:01 on 04/28/95.
-----------------------------------------------------------------------------
Memory operation in C:\DEV\EXAMPLE2.C, line 327:
                                   allocating a 36-byte 'Client' block (# 13)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 14)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 15)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 16)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 17)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 18)
Assert: C:\DEV\EXAMPLE2.C(219) : Assertion failed:
                                    ( bday->Day > 0 ) && ( bday->Day < 32 )
Warning: DAMAGE: after (null) block (#17) at 0x00661C68.
Warning: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661B38Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661B84Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661BD0Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661C1CError: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661C68Error: DAMAGE: after (null) block (#17) at 0x00661C68.

Debug Functions


_CrtSetReportFile

Identifies the file or stream to be used by _CrtDbgReport as a destination for a specific report type (debug version only).

_HFILE _CrtSetReportFile( int reportType, _HFILE reportFile );

Routine | Required Header | Compatibility
_CrtSetReportFile | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

Upon successful completion, _CrtSetReportFile returns the previous report file defined for the report type specified in reportType. If an error occurs, the report file for reportType is not modified and_CrtSetReportFile returns _CRTDBG_HFILE_ERROR.

Parameters

reportType

Report type: _CRT_WARN, _CRT_ERROR, _CRT_ASSERT

reportFile

New report file for reportType, see the following table

Remarks

_CrtSetReportFile is used in conjunction with the _CrtSetReportMode function to define the destination(s) for a specific report type generated by _CrtDbgReport. When _CrtSetReportMode has been called to assign the _CRTDBG_MODE_FILE reporting mode for a specific report type, _CrtSetReportFile should then be called to define the specific file or stream to use as the destination. When _DEBUG is not defined, calls to _CrtSetReportFile are removed during preprocessing.

The _CrtSetReportFile function assigns the new report file specified in reportFile to the report type specified in reportType and returns the previously defined report file for reportType. The following table lists the available choices for reportFile and the resulting behavior of _CrtDbgReport. These options are defined as bit-flags in CRTDBG.H.

Report File | _CrtDbgReport Behavior
_HFILE | _CrtDbgReport writes the message to a user-supplied HANDLE and does not verify the validity of the file handle. The application is responsible for opening and closing the report file and passing a valid file handle.
_CRTDBG_FILE_STDERR | _CrtDbgReport writes message to stderr.
_CRTDBG_FILE_STDOUT | _CrtDbgReport writes message to stdout.
_CRTDBG_REPORT_FILE | _CrtDbgReport is not called and the report file for reportType is not modified. _CrtSetReportFile simply returns the current report file for reportType.

When the report destination is a file, _CrtSetReportMode is called to set the file bit-flag and _CrtSetReportFile is called to define the specific file to use. The following code fragment demonstrates this configuration:

_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );

The report file used by each report type can be separately controlled. For example, it is possible to specify that a reportType of _CRT_ERROR be reported to stderr, while a reportType of _CRT_ASSERT be reported to a user-defined file handle or stream.

For more information about defining the report mode(s) and file for a specific report type, see _CrtDbgReport, _CrtSetReportMode and the section Debug Reporting Functions of the C Run-Time Library.

Example

/*
 * REPORT.C:
 * In this program, calls are made to the _CrtSetReportMode,
 * _CrtSetReportFile, and _CrtSetReportHook functions.
 * The _ASSERT macros are called to evaluate their expression.
 * When the condition fails, these macros print a diagnostic message
 * and call _CrtDbgReport to generate a debug report and the
 * client-defined reporting function is called as well.
 * The _RPTn and _RPTFn group of macros are also exercised in
 * this program, as an alternative to the printf function.
 * When these macros are called, the client-defined reporting function
 * takes care of all the reporting - _CrtDbgReport won't be called.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

/*
 * Define our own reporting function.
 * We'll hook it into the debug reporting
 * process later using _CrtSetReportHook.
 *
 * Define a global int to keep track of
 * how many assertion failures occur.
 */
int gl_num_asserts=0;
int OurReportingFunction( int reportType, char *userMessage, int *retVal )
{
   /*
    * Tell the user our reporting function is being called.
    * In other words - verify that the hook routine worked.
    */
   fprintf("Inside the client-defined reporting function.\n", STDOUT);
   fflush(STDOUT);

   /*
    * When the report type is for an ASSERT,
    * we'll report some information, but we also
    * want _CrtDbgReport to get called -
    * so we'll return TRUE.
    *
    * When the report type is a WARNing or ERROR,
    * we'll take care of all of the reporting. We don't
    * want _CrtDbgReport to get called -
    * so we'll return FALSE.
    */
   if (reportType == _CRT_ASSERT)
   {
      gl_num_asserts++;
      fprintf("This is the number of Assertion failures that have occurred: %d \n", gl_num_asserts, STDOUT);
      fflush(STDOUT);
      fprintf("Returning TRUE from the client-defined reporting function.\n", STDOUT);
      fflush(STDOUT);
      return(TRUE);
   } else {
      fprintf("This is the debug user message: %s \n", userMessage, STDOUT);
      fflush(STDOUT);
      fprintf("Returning FALSE from the client-defined reporting function.\n", STDOUT);
      fflush(STDOUT);
      return(FALSE);
   }

   /*
    * By setting retVal to zero, we are instructing _CrtDbgReport
    * to continue with normal execution after generating the report.
    * If we wanted _CrtDbgReport to start the debugger, we would set
    * retVal to one.
    */
   retVal = 0;
}

int main()
{
      char *p1, *p2;

   /*
    * Hook in our client-defined reporting function.
    * Every time a _CrtDbgReport is called to generate
    * a debug report, our function will get called first.
    */
   _CrtSetReportHook( OurReportingFunction );

   /*
    * Define the report destination(s) for each type of report
    * we are going to generate.  In this case, we are going to
    * generate a report for every report type: _CRT_WARN,
    * _CRT_ERROR, and _CRT_ASSERT.
    * The destination(s) is defined by specifying the report mode(s)
    * and report file for each report type.
    * This program sends all report types to STDOUT.
    */
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   /*
    * Allocate and assign the pointer variables
    */
   p1 = malloc(10);
   strcpy(p1, "I am p1");
   p2 = malloc(10);
   strcpy(p2, "I am p2");

   /*
    * Use the report macros as a debugging
    * warning mechanism, similar to printf.
    *
    * Use the assert macros to check if the
    * p1 and p2 variables are equivalent.
    *
    * If the expression fails, _ASSERTE will
    * include a string representation of the
    * failed expression in the report.
    *
    *  _ASSERT does not include the
    * expression in the generated report.
    */
   _RPT0(_CRT_WARN, "\n\n Use the assert macros to evaluate the expression p1 == p2.\n");
   _RPTF2(_CRT_WARN, "\n Will _ASSERT find '%s' == '%s' ?\n", p1, p2);
   _ASSERT(p1 == p2);

   _RPTF2(_CRT_WARN, "\n\n Will _ASSERTE find '%s' == '%s' ?\n", p1, p2);
   _ASSERTE(p1 == p2);

   _RPT2(_CRT_ERROR, "\n \n '%s' != '%s'\n", p1, p2);

   free(p2);
   free(p1);

   return 0;
}

Output

Inside the client-defined reporting function.
This is the debug user message: Use the assert macros to evaluate the expression p1 == p2
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(54) : Will _ASSERT find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 1
Returning TRUE from the client-defined reporting function.
dbgmacro.c(55) : Assertion failed
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(57) : Will _ASSERTE find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 2
Returning TRUE from the client-defined reporting function.
dbgmacro.c(58) : Assertion failed: p1 == p2
Inside the client-defined reporting function.
This is the debug user message: 'I am p1' != 'I am p2'
Returning FALSE from the client-defined reporting function.

Debug Functions

See Also _CrtDbgReport


_CrtSetReportHook

Installs a client-defined reporting function by hooking it into the C run-time debug reporting process (debug version only).

_CRT_REPORT_HOOK _CrtSetReportHook( _CRT_REPORT_HOOK reportHook );

Routine | Required Header | Compatibility
_CrtSetReportHook | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

_CrtSetReportHook returns the previous client-defined reporting function.

Parameter

reportHook

New client-defined reporting function to hook into the C run-time debug reporting process

Remarks

_CrtSetReportHook allows an application to use its own reporting function into the C run-time debug library reporting process. As a result, whenever _CrtDbgReport is called to generate a debug report, the application’s reporting function is called first. This functionality enables an application to perform operations such as filtering debug reports so it can focus on specific allocation types or send a report to destinations not available by using _CrtDbgReport. When _DEBUG is not defined, calls to _CrtSetReportHook are removed during preprocessing.

The _CrtSetReportHook function installs the new client-defined reporting function specified in reportHook and returns the previous client-defined hook. The following example demonstrates how a client-defined report hook should be prototyped:

int YourReportHook( int reportType, char *message, int *returnValue );

where reportType is the debug report type (_CRT_WARN, _CRT_ERROR, _CRT_ASSERT), message is the fully assembled debug user message to be contained in the report, and returnValue is the value specified by the client-defined reporting function that should be returned by _CrtDbgReport. See the _CrtSetReportMode function for a complete description of the available report types.

If the client-defined reporting function completely handles the debug message such that no further reporting is required, then the function should return TRUE. When the function returns FALSE, _CrtDbgReport will be called to generate the debug report using the current settings for the report type, mode, and file. In addition, by specifying the _CrtDbgReport return value in returnValue, the application can also control whether a debug break occurs. See _CrtSetReportMode, _CrtSetReportFile, and _CrtDbgReport for a complete description of how the debug report is configured and generated.

For more information about other hook-capable run-time functions and writing your own client-defined hook functions, see Writing Your Own Debug Hook Functions.

Example

/*
 * REPORT.C:
 * In this program, calls are made to the _CrtSetReportMode,
 * _CrtSetReportFile, and _CrtSetReportHook functions.
 * The _ASSERT macros are called to evaluate their expression.
 * When the condition fails, these macros print a diagnostic message
 * and call _CrtDbgReport to generate a debug report and the
 * client-defined reporting function is called as well.
 * The _RPTn and _RPTFn group of macros are also exercised in
 * this program, as an alternative to the printf function.
 * When these macros are called, the client-defined reporting function
 * takes care of all the reporting - _CrtDbgReport won't be called.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

/*
 * Define our own reporting function.
 * We'll hook it into the debug reporting
 * process later using _CrtSetReportHook.
 *
 * Define a global int to keep track of
 * how many assertion failures occur.
 */
int gl_num_asserts=0;
int OurReportingFunction( int reportType, char *userMessage, int *retVal )
{
   /*
    * Tell the user our reporting function is being called.
    * In other words - verify that the hook routine worked.
    */
   fprintf("Inside the client-defined reporting function.\n", STDOUT);
   fflush(STDOUT);

   /*
    * When the report type is for an ASSERT,
    * we'll report some information, but we also
    * want _CrtDbgReport to get called -
    * so we'll return TRUE.
    *
    * When the report type is a WARNing or ERROR,
    * we'll take care of all of the reporting. We don't
    * want _CrtDbgReport to get called -
    * so we'll return FALSE.
    */
   if (reportType == _CRT_ASSERT)
   {
      gl_num_asserts++;
      fprintf("This is the number of Assertion failures that have occurred: %d \n", gl_num_asserts, STDOUT);
      fflush(STDOUT);
      fprintf("Returning TRUE from the client-defined reporting function.\n", STDOUT);
      fflush(STDOUT);
      return(TRUE);
   } else {
      fprintf("This is the debug user message: %s \n", userMessage, STDOUT);
      fflush(STDOUT);
      fprintf("Returning FALSE from the client-defined reporting function.\n", STDOUT);
      fflush(STDOUT);
      return(FALSE);
   }

   /*
    * By setting retVal to zero, we are instructing _CrtDbgReport
    * to continue with normal execution after generating the report.
    * If we wanted _CrtDbgReport to start the debugger, we would set
    * retVal to one.
    */
   retVal = 0;
}

int main()
{
      char *p1, *p2;

   /*
    * Hook in our client-defined reporting function.
    * Every time a _CrtDbgReport is called to generate
    * a debug report, our function will get called first.
    */
   _CrtSetReportHook( OurReportingFunction );

   /*
    * Define the report destination(s) for each type of report
    * we are going to generate.  In this case, we are going to
    * generate a report for every report type: _CRT_WARN,
    * _CRT_ERROR, and _CRT_ASSERT.
    * The destination(s) is defined by specifying the report mode(s)
    * and report file for each report type.
    * This program sends all report types to STDOUT.
    */
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   /*
    * Allocate and assign the pointer variables
    */
   p1 = malloc(10);
   strcpy(p1, "I am p1");
   p2 = malloc(10);
   strcpy(p2, "I am p2");

   /*
    * Use the report macros as a debugging
    * warning mechanism, similar to printf.
    *
    * Use the assert macros to check if the
    * p1 and p2 variables are equivalent.
    *
    * If the expression fails, _ASSERTE will
    * include a string representation of the
    * failed expression in the report.
    *
    *  _ASSERT does not include the
    * expression in the generated report.
    */
   _RPT0(_CRT_WARN, "\n\n Use the assert macros to evaluate the expression p1 == p2.\n");
   _RPTF2(_CRT_WARN, "\n Will _ASSERT find '%s' == '%s' ?\n", p1, p2);
   _ASSERT(p1 == p2);

   _RPTF2(_CRT_WARN, "\n\n Will _ASSERTE find '%s' == '%s' ?\n", p1, p2);
   _ASSERTE(p1 == p2);

   _RPT2(_CRT_ERROR, "\n \n '%s' != '%s'\n", p1, p2);

   free(p2);
   free(p1);

   return 0;
}

Output

Inside the client-defined reporting function.
This is the debug user message: Use the assert macros to evaluate the expression p1 == p2
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(54) : Will _ASSERT find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 1
Returning TRUE from the client-defined reporting function.
dbgmacro.c(55) : Assertion failed
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(57) : Will _ASSERTE find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 2
Returning TRUE from the client-defined reporting function.
dbgmacro.c(58) : Assertion failed: p1 == p2
Inside the client-defined reporting function.
This is the debug user message: 'I am p1' != 'I am p2'
Returning FALSE from the client-defined reporting function.

Debug Functions


_CrtSetReportMode

Specifies the general destination(s) for a specific report type generated by _CrtDbgReport (debug version only).

int _CrtSetReportMode( int reportType, int reportMode );

Routine | Required Header | Compatibility
_CrtSetReportMode | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

Upon successful completion, _CrtSetReportMode returns the previous report mode(s) for the report type specified in reportType. If an error occurs, the report mode(s) for reportType are not modified and_CrtSetReportMode returns –1.

Parameters

reportType

Report type: _CRT_WARN, _CRT_ERROR, _CRT_ASSERT

reportMode

New report mode(s) for reportType, see the table in the Remarks section

Remarks

_CrtSetReportMode is used in conjunction with the _CrtSetReportFile function to define the destination(s) for a specific report type generated by _CrtDbgReport. If _CrtSetReportMode and _CrtSetReportFile are not called to define the reporting method(s) for a specific report type, then _CrtDbgReport generates the report type using default destinations: Assertion failures and errors are directed to a debug message window, warnings from Windows applications are sent to the debugger, and warnings from console applications are directed to stderr. When _DEBUG is not defined, calls to _CrtSetReportMode are removed during preprocessing.

The following table lists the report types defined in CRTDBG.H.

Report Type | Description
_CRT_WARN | Warnings, messages, and information that does not need immediate attention.
_CRT_ERROR | Errors, unrecoverable problems, and issues that require immediate attention.
_CRT_ASSERT | Assertion failures (asserted expressions that evaluate to FALSE).

The _CrtSetReportMode function assigns the new report mode specified in reportMode to the report type specified in reportType and returns the previously defined report mode for reportType. The following table lists the available choices for reportMode and the resulting behavior of _CrtDbgReport. These options are defined as bit-flags in CRTDBG.H.

Report Mode | _CrtDbgReport Behavior
_CRTDBG_MODE_DEBUG | Writes the message to an output debug string.
_CRTDBG_MODE_FILE | Writes the message to a user-supplied file handle. _CrtSetReportFile should be called to define the specific file or stream to use as the destination.
_CRTDBG_MODE_WNDW | Creates a message box to display the message along with the Abort, Retry, and Ignore buttons.
_CRTDBG_REPORT_MODE | It is not called, and the report mode for reportType is not modified. _CrtSetReportMode simply returns the current report mode for reportType.

Each report type may be reported using one, two, or three modes, or no mode at all. Therefore, it is possible to have more than one destination defined for a single report type. For example, the following code fragment causes assertion failures to be sent to both a debug message window and to stderr:

_CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE | _CRTDBG_MODE_WNDW );
_CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );

In addition, the reporting mode(s) for each report type can be separately controlled. For example, it is possible to specify that a reportType of _CRT_WARN be sent to an output debug string, while _CRT_ASSERT be displayed using a a debug message window and sent to stderr, as illustrated above.

For more information about defining the report mode(s) and file for a specific report type, see _CrtDbgReport, _CrtSetReportFile and the section Debug Reporting Functions of the C Run-Time Library.

Example

/*
 * REPORT.C:
 * In this program, calls are made to the _CrtSetReportMode,
 * _CrtSetReportFile, and _CrtSetReportHook functions.
 * The _ASSERT macros are called to evaluate their expression.
 * When the condition fails, these macros print a diagnostic message
 * and call _CrtDbgReport to generate a debug report and the
 * client-defined reporting function is called as well.
 * The _RPTn and _RPTFn group of macros are also exercised in
 * this program, as an alternative to the printf function.
 * When these macros are called, the client-defined reporting function
 * takes care of all the reporting - _CrtDbgReport won't be called.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

/*
 * Define our own reporting function.
 * We'll hook it into the debug reporting
 * process later using _CrtSetReportHook.
 *
 * Define a global int to keep track of
 * how many assertion failures occur.
 */
int gl_num_asserts=0;
int OurReportingFunction( int reportType, char *userMessage, int *retVal )
{
   /*
    * Tell the user our reporting function is being called.
    * In other words - verify that the hook routine worked.
    */
   fprintf("Inside the client-defined reporting function.\n", STDOUT);
   fflush(STDOUT);

   /*
    * When the report type is for an ASSERT,
    * we'll report some information, but we also
    * want _CrtDbgReport to get called -
    * so we'll return TRUE.
    *
    * When the report type is a WARNing or ERROR,
    * we'll take care of all of the reporting. We don't
    * want _CrtDbgReport to get called -
    * so we'll return FALSE.
    */
   if (reportType == _CRT_ASSERT)
   {
      gl_num_asserts++;
      fprintf("This is the number of Assertion failures that have occurred: %d \n", gl_num_asserts, STDOUT);
      fflush(STDOUT);
      fprintf("Returning TRUE from the client-defined reporting function.\n", STDOUT);
      fflush(STDOUT);
      return(TRUE);
   } else {
      fprintf("This is the debug user message: %s \n", userMessage, STDOUT);
      fflush(STDOUT);
      fprintf("Returning FALSE from the client-defined reporting function.\n", STDOUT);
      fflush(STDOUT);
      return(FALSE);
   }

   /*
    * By setting retVal to zero, we are instructing _CrtDbgReport
    * to continue with normal execution after generating the report.
    * If we wanted _CrtDbgReport to start the debugger, we would set
    * retVal to one.
    */
   retVal = 0;
}

int main()
{
      char *p1, *p2;

   /*
    * Hook in our client-defined reporting function.
    * Every time a _CrtDbgReport is called to generate
    * a debug report, our function will get called first.
    */
   _CrtSetReportHook( OurReportingFunction );

   /*
    * Define the report destination(s) for each type of report
    * we are going to generate.  In this case, we are going to
    * generate a report for every report type: _CRT_WARN,
    * _CRT_ERROR, and _CRT_ASSERT.
    * The destination(s) is defined by specifying the report mode(s)
    * and report file for each report type.
    * This program sends all report types to STDOUT.
    */
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   /*
    * Allocate and assign the pointer variables
    */
   p1 = malloc(10);
   strcpy(p1, "I am p1");
   p2 = malloc(10);
   strcpy(p2, "I am p2");

   /*
    * Use the report macros as a debugging
    * warning mechanism, similar to printf.
    *
    * Use the assert macros to check if the
    * p1 and p2 variables are equivalent.
    *
    * If the expression fails, _ASSERTE will
    * include a string representation of the
    * failed expression in the report.
    *
    *  _ASSERT does not include the
    * expression in the generated report.
    */
   _RPT0(_CRT_WARN, "\n\n Use the assert macros to evaluate the expression p1 == p2.\n");
   _RPTF2(_CRT_WARN, "\n Will _ASSERT find '%s' == '%s' ?\n", p1, p2);
   _ASSERT(p1 == p2);

   _RPTF2(_CRT_WARN, "\n\n Will _ASSERTE find '%s' == '%s' ?\n", p1, p2);
   _ASSERTE(p1 == p2);

   _RPT2(_CRT_ERROR, "\n \n '%s' != '%s'\n", p1, p2);

   free(p2);
   free(p1);

   return 0;
}

Output

Inside the client-defined reporting function.
This is the debug user message: Use the assert macros to evaluate the expression p1 == p2
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(54) : Will _ASSERT find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 1
Returning TRUE from the client-defined reporting function.
dbgmacro.c(55) : Assertion failed
Inside the client-defined reporting function.
This is the debug user message: dbgmacro.c(57) : Will _ASSERTE find 'I am p1' == 'I am p2' ?
Returning FALSE from the client-defined reporting function.
Inside the client-defined reporting function.
This is the number of Assertion failures that have occurred: 2
Returning TRUE from the client-defined reporting function.
dbgmacro.c(58) : Assertion failed: p1 == p2
Inside the client-defined reporting function.
This is the debug user message: 'I am p1' != 'I am p2'
Returning FALSE from the client-defined reporting function.

Debug Functions


_expand_dbg

Resizes a specified block of memory in the heap by expanding or contracting the block (debug version only).

void *_expand_dbg( void *userData, size_t newSize, int blockType, const char *filename, int linenumber );

Routine | Required Header | Compatibility
_expand_dbg | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

Upon successful completion, _expand_dbg returns a pointer to the resized memory block, otherwise it returns NULL.

Parameters

userData

Pointer to the previously allocated memory block

newSize

Requested new size for block (bytes)

blockType

Requested type for resized block: _CLIENT_BLOCK or _NORMAL_BLOCK

filename

Pointer to name of source file that requested expand operation or NULL

linenumber

Line number in source file where expand operation was requested or NULL

The filename and linenumber parameters are only available when _expand_dbg has been called explicitly or the _CRTDBG_MAP_ALLOC preprocessor constant has been defined.

Remarks

The _expand_dbg function is a debug version of the _expand function. When _DEBUG is not defined, calls to _expand_dbg are removed during preprocessing. Both _expand and _expand_dbg resize a memory block in the base heap, but _expand_dbg accomodates several debugging features: buffers on either side of the user portion of the block to test for leaks, a block type parameter to track specific allocation types, and filename/linenumber information to determine the origin of allocation requests.

_expand_dbg resizes the specified memory block with slightly more space than the requested newSize. newSize may be greater or less than the size of the originally allocated memory block. The additional space is used by the debug heap manager to link the debug memory blocks together and to provide the application with debug header information and overwrite buffers. The resize is accomplished by either expanding or contracting the original memory block. _expand_dbg does not move the memory block, as does the _realloc_dbg function.

When newSize is greater than the original block size, the memory block is expanded. During an expansion, if the memory block cannot be expanded to accommodate the requested size, the block is expanded as much as possible. When newSize is less than the original block size, the memory block is contracted until the new size is obtained.

For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap. For information about the allocation block types and how they are used, see Types of Blocks on the Debug Heap.. For information on the differences between calling a standard heap function versus its debug version in a debug build of an application, see Using the Debug Version Versus the Base Version..

Example

/*
 * EXPANDD.C
 * This program allocates a block of memory using _malloc_dbg
 * and then calls _msize_dbg to display the size of that block.
 * Next, it uses _expand_dbg to expand the amount of
 * memory used by the buffer and then calls _msize_dbg again to
 * display the new amount of memory allocated to the buffer.
 */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <crtdbg.h>

void main( void )
{
        long *buffer;
        size_t size;

        /*
         * Call _malloc_dbg to include the filename and line number
         * of our allocation request in the header
         */
        buffer = (long *)_malloc_dbg( 40 * sizeof(long), _NORMAL_BLOCK, __FILE__, __LINE__ );
        if( buffer == NULL )
               exit( 1 );

        /*
         * Get the size of the buffer by calling _msize_dbg
         */
        size = _msize_dbg( buffer, _NORMAL_BLOCK );
        printf( "Size of block after _malloc_dbg of 40 longs: %u\n", size );

        /*
         * Expand the buffer using _expand_dbg and show the new size
         */
        buffer = _expand_dbg( buffer, size + (40 * sizeof(long)), _NORMAL_BLOCK, __FILE__, __LINE__ );
        if( buffer == NULL )
               exit( 1 );
        size = _msize_dbg( buffer, _NORMAL_BLOCK );
        printf( "Size of block after _expand_dbg of 40 more longs: %u\n", size );

        free( buffer );
        exit( 0 );
}

Output

Size of block after _malloc_dbg of 40 longs: 160
Size of block after _expand_dbg of 40 more longs: 320

Debug Functions

See Also _malloc_dbg


_free_dbg

Frees a block of memory in the heap (debug version only).

void _free_dbg( void *userData, int blockType );

Routine | Required Header | Compatibility
_free_dbg | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

None

Parameters

userData

Pointer to the allocated memory block to be freed

blockType

Type of allocated memory block to be freed: _CLIENT_BLOCK, _NORMAL_BLOCK, or _IGNORE_BLOCK

Remarks

The _free_dbg function is a debug version of the free function. When _DEBUG is not defined, calls to _free_dbg are removed during preprocessing. Both free and _free_dbg free a memory block in the base heap, but _free_dbg accomodates two debugging features: the ability to keep freed blocks in the heap’s linked list to simulate low memory conditions and a block type parameter to free specific allocation types.

_free_dbg performs a validity check on all specified files and block locations before performing the free operation?the application is not expected to provide this information. When a memory block is freed, the debug heap manager automatically checks the integrity of the buffers on either side of the user portion and issues an error report if overwriting has occurred. If the _CRTDBG_DELAY_FREE_MEM_DF bit field of the _crtDbgFlag flag is set, the freed block is filled with the value 0xDD, assigned the _FREE_BLOCK block type, and kept in the heap’s linked list of memory blocks.

For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap. For information about the allocation block types and how they are used, see Types of Blocks on the Debug Heap. For information on the differences between calling a standard heap function versus its debug version in a debug build of an application, see Using the Debug Version Versus the Base Version.

Example

/*****************************************************************
 *  EXAMPLE  2                                                   *
 *  ----------                                                   *
 *  This program illustrates several ways to use debugging hook  *
 *  functions with the new debug versions of the C runtime       *
 *  libraries. To add some realism, it has a few elements of an  *
 *  actual application, including two bugs.                      *
 *                                                               *
 *  The program stores birthdate information in a linked list    *
 *  of Client blocks. A Client-dump hook function validates the  *
 *  birthday data and reports the contents of the Client blocks. *
 *  An allocation hook function logs heap operations to a text   *
 *  file, and the report hook function logs reports to the same  *
 *  text file.                                                   *
 *                                                               *
 *  NOTE: The allocation hook function explicitly excludes CRT   *
 *        blocks (the memory allocated internally by the C       *
 *        runtime library) from its log. It is important to      *
 *        understand why! The hook function uses fprintf( ) to   *
 *        write to the log file, and fprintf( ) allocates a CRT  *
 *        block. If CRT blocks were not excluded in this case,   *
 *        an endless loop would be created in which fprintf( )   *
 *        would cause the hook function to be called, and the    *
 *        hook would in turn call fprintf( ), which would cause  *
 *        the hook to be called again, and so on. The moral is:  *
 *                                                               *
 *   -->  IF YOUR ALLOCATION HOOK USES ANY C RUNTIME FUNCTION    *
 *        THAT ALLOCATES MEMORY, THE HOOK MUST IGNORE CRT-TYPE   *
 *        ALLOCATION OPERATIONS!                                 *
 *                                                               *
 *  HINT: If you want to be able to report CRT-type blocks in    *
 *        your allocation hook, use Windows API functions for    *
 *        formatting and output, instead of C runtime functions. *
 *        Since the Windows APIs do not use the CRT heap, they   *
 *        will not trap your hook in an endless loop.            *
 *                                                               *
 *  BUGS: There are two bugs in the program below, which the     *
 *        debug heap features identify in several ways. One bug  *
 *        is that the birthDay.Name field is not large enough    *
 *        to hold several of the test names. The field should    *
 *        be larger, and strncpy( ) should be used in place of   *
 *        strcpy( ). The second bug is that the while( ) loop    *
 *        in the printRecords( ) function should not end until   *
 *        HeadPtr itself == NULL. This bug results not only in   *
 *        an incomplete display of birthdays, but also in a      *
 *        memory leak. In addition to these two bugs, Gauss'     *
 *        birthday data is out of range (April 30, not 32).      *
 *                                                               *
 *****************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <time.h>
#include <crtdbg.h>

/*****************************************************************
 *  DATA DECLARATIONS AND DEFINES                                *
 *****************************************************************/

// The following arrays provide test data for the example program:
const char * Names[] =
{
   "George Washington",
   "Thomas Jefferson",
   "Carl Friedrich Gauss",
   "Ludwig van Beethoven",
   "Thomas Carlyle"
} ;

const int Dates[] =
{
   1732,  2, 11,
   1743,  4, 13,
   1777,  4, 32,
   1795, 12,  4,
   1770, 12, 16
} ;

#define  TEST_RECS            5
// A generic sort of linked-list data structure, in this case for birthdays:
typedef struct BirthdayStruct
{
   struct BirthdayStruct * NextRec;
   int   Year;
   int   Month;
   int   Day;
   char  Name[20];
} birthDay;

birthDay * HeadPtr;
birthDay * TailPtr;

#define  FILE_IO_ERROR        0
#define  OUT_OF_MEMORY        1

#define  TRUE                 7
#define  FALSE                0

// Macros for setting or clearing bits in the CRT debug flag
#ifdef _DEBUG
#define  SET_CRT_DEBUG_FIELD(a)   _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

/*****************************************************************
 *  SPECIAL-PURPOSE ROUTINES                                     *
 *****************************************************************/

/* ERROR HANDLER
   -------------
   Handling serious errors gracefully is a real test of craftsmanship.
   This function is just a stub; it doesn't really handle errors.
*/
void FatalError( int ErrType )
{
   exit( 1 );
}

/* MEMORY ALLOCATION FUNCTION
   --------------------------
   The createRecord function allocates memory for a new birthday record,
   fills in the structure members, and then adds the record to a linked list.
   In debug builds, it makes these allocations in Client blocks. If memory
   is not available, it calls the error handler.
*/
void createRecord(
   const int    Year,
   const int    Month,
   const int    Day,
   const char * Name
#ifdef _DEBUG
,  const unsigned char * szFileName, int nLine
#endif
   )
{
   birthDay * ptr;
   size_t n;

   n = sizeof( struct BirthdayStruct );
   ptr = (birthDay *) _malloc_dbg( n, _CLIENT_BLOCK, szFileName, nLine );
   if( ptr == NULL )
      FatalError( OUT_OF_MEMORY );
   ptr->Year = Year;
   ptr->Month = Month;
   ptr->Day = Day;
   strcpy( ptr->Name, Name );

   ptr->NextRec = NULL;
   if ( HeadPtr == NULL )     // If this is the first record in the linked list
      HeadPtr = ptr;
   else
      TailPtr->NextRec = ptr;
   TailPtr = ptr;
}

/* BIRTHDAY DISPLAY FUNCTION
   -------------------------
   This function traverses the linked list, displays the birthday data,
   and then frees the memory blocks used to store the birthdays.
*/
void printRecords( )
{
   birthDay * ptr;
   char *months[] = {
      "", "January", "February", "March", "April", "May", "June", "July",
      "August", "September", "October", "November", "December" };

   if ( HeadPtr == NULL )        // Do nothing if list is empty
      return;

   printf( "\n\nThis is the birthday list:\n" );
   while ( HeadPtr->NextRec != NULL )
   {
      printf( "   %s was born on %s %d, %d.\n",
              HeadPtr->Name, months[HeadPtr->Month], HeadPtr->Day, HeadPtr->Year );
      ptr = HeadPtr->NextRec;
      _free_dbg( HeadPtr, _CLIENT_BLOCK );
      HeadPtr = ptr;
   }
}

/*****************************************************************
 *  DEBUG C RUNTIME LIBRARY HOOK FUNCTIONS AND DEFINES           *
 *****************************************************************/
#ifdef _DEBUG
#define  createRecord(a, b, c, d) \
         createRecord(a, b, c, d, __FILE__, __LINE__)
FILE *logFile;                // Used to log allocation information
const char lineStr[] = { "---------------------------------------\
--------------------------------------\n"  };

/* CLIENT DUMP HOOK FUNCTION
   -------------------------
   A hook function for dumping a Client block usually reports some
   or all of the contents of the block in question.  The function
   below also checks the data in several ways, and reports corruption
   or inconsistency as an assertion failure.
*/
void __cdecl MyDumpClientHook(
   void * pUserData,
   size_t nBytes
   )
{
   birthDay * bday;

   bday = (birthDay *) pUserData;

   _RPT4( _CRT_WARN, "   The birthday of %s is %d/%d/%d.\n",
          bday->Name, bday->Month, bday->Day, bday->Year );
   _ASSERTE( ( bday->Day > 0 ) && ( bday->Day < 32 ) );
   _ASSERTE( ( bday->Month > 0 ) && ( bday->Month < 13 ) );
   _ASSERTE( ( bday->Year > 0 ) && ( bday->Year < 1996 ) );
}

/* ALLOCATION HOOK FUNCTION
   -------------------------
   An allocation hook function can have many, many different
   uses. This one simply logs each allocation operation in a file.
*/
int __cdecl MyAllocHook(
   int      nAllocType,
   void   * pvData,
   size_t   nSize,
   int      nBlockUse,
   long     lRequest,
   const unsigned char * szFileName,
   int      nLine
   )
{
   char *operation[] = { "", "allocating", "re-allocating", "freeing" };
   char *blockType[] = { "Free", "Normal", "CRT", "Ignore", "Client" };

   if ( nBlockUse == _CRT_BLOCK )   // Ignore internal C runtime library allocations
      return( TRUE );

   _ASSERT( ( nAllocType > 0 ) && ( nAllocType < 4 ) );
   _ASSERT( ( nBlockUse >= 0 ) && ( nBlockUse < 5 ) );

   fprintf( logFile,
            "Memory operation in %s, line %d: %s a %d-byte '%s' block (# %ld)\n",
            szFileName, nLine, operation[nAllocType], nSize,
            blockType[nBlockUse], lRequest );
   if ( pvData != NULL )
      fprintf( logFile, " at %X", pvData );

   return( TRUE );         // Allow the memory operation to proceed
}

/* REPORT HOOK FUNCTION
   --------------------
   Again, report hook functions can serve a very wide variety of purposes.
   This one logs error and assertion failure debug reports in the
   log file, along with 'Damage' reports about overwritten memory.

   By setting the retVal parameter to zero, we are instructing _CrtDbgReport
   to return zero, which causes execution to continue. If we want the function
   to start the debugger, we should have _CrtDbgReport return one.
*/
int MyReportHook(
   int   nRptType,
   char *szMsg,
   int  *retVal
   )
{
   char *RptTypes[] = { "Warning", "Error", "Assert" };

   if ( ( nRptType > 0 ) || ( strstr( szMsg, "DAMAGE" ) ) )
      fprintf( logFile, "%s: %s", RptTypes[nRptType], szMsg );

   retVal = 0;

   return( TRUE );         // Allow the report to be made as usual

}
#endif                     // End of #ifdef _DEBUG

/*****************************************************************
 *  MAIN FUNCTION                                                *
 *****************************************************************/
void main( )
{
   int i, j;

#ifdef _DEBUG
   _CrtMemState checkPt1;
   char timeStr[10], dateStr[10];         // Used to set up log file

   // Send all reports to STDOUT, since this example is a console app
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   // Set the debug heap to report memory leaks when the process terminates,
   // and to keep freed blocks in the linked list.
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF | _CRTDBG_DELAY_FREE_MEM_DF );

   // Open a log file for the hook functions to use
   logFile = fopen( "MEM-LOG.TXT", "w" );
   if ( logFile == NULL )
      FatalError( FILE_IO_ERROR );
   _strtime( timeStr );
   _strdate( dateStr );
   fprintf( logFile,
            "Memory Allocation Log File for Example Program, run at %s on %s.\n",
            timeStr, dateStr );
   fputs( lineStr, logFile );

   // Install the hook functions
   _CrtSetDumpClient( MyDumpClientHook );
   _CrtSetAllocHook( MyAllocHook );
   _CrtSetReportHook( MyReportHook );

#endif                     // End of #ifdef _DEBUG

   HeadPtr = NULL;

   // Create a trial birthday record.
   createRecord( 1749, 3, 23, "Pierre de Laplace" );

   // Check the debug heap, and dump the new birthday record. --Note that
   // debug C runtime library functions such as _CrtCheckMemory( ) and
   // _CrtMemDumpAllObjectsSince( ) automatically disappear in a release build.
   _CrtMemDumpAllObjectsSince( NULL );
   _CrtCheckMemory( );
   _CrtMemCheckpoint( &checkPt1 );

   // Since everything has worked so far, create more records
   for ( i = 0, j = 0; i < TEST_RECS; i++, j+=3 )
      createRecord( Dates[j], Dates[j+1], Dates[j+2], Names[i] );

   // Examine the results
   _CrtMemDumpAllObjectsSince( &checkPt1 );
   _CrtMemCheckpoint( &checkPt1 );
   _CrtMemDumpStatistics( &checkPt1 );
   _CrtCheckMemory( );

   // This fflush needs to be removed...
   fflush( logFile );

   // Now try displaying the records, which frees the memory being used
   printRecords( );

   // OK, time to go. Did I forget to turn out any lights? I could check
   // explicitly using _CrtDumpMemoryLeaks( ), but I have set
   // _CRTDBG_LEAK_CHECK_DF, so the C runtime library debug heap will
   // automatically alert me at exit of any memory leaks.

#ifdef _DEBUG
   fclose( logFile );
#endif
}

Output

Screen output:

Dumping objects ->
C:\DEV\EXAMPLE2.C(327) : {13} client block at 0x00661B38, subtype 0, 36 bytes long:
   The birthday of Pierre de Laplace is 3/23/1749.
Object dump complete.
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
C:\DEV\EXAMPLE2.C(338) : {17} client block at 0x00661C68, subtype 0, 36 bytes long:
   The birthday of Ludwig van Beethoven is 12/4/1795.
C:\DEV\EXAMPLE2.C(338) : {16} client block at 0x00661C1C, subtype 0, 36 bytes long:
   The birthday of Carl Friedrich Gauss is 4/32/1777.
C:\DEV\EXAMPLE2.C(219) : Assertion failed: ( bday->Day > 0 ) && ( bday->Day < 32 )
C:\DEV\EXAMPLE2.C(338) : {15} client block at 0x00661BD0, subtype 0, 36 bytes long:
   The birthday of Thomas Jefferson is 4/13/1743.
C:\DEV\EXAMPLE2.C(338) : {14} client block at 0x00661B84, subtype 0, 36 bytes long:
   The birthday of George Washington is 2/11/1732.
Object dump complete.
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
6442 bytes in 12 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
216 bytes in 6 (null) Blocks.
Largest number used: 6658 bytes.
Total allocations: 6658 bytes.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C68 is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
(null) allocated at file C:\DEV\EXAMPLE2.C(338).
(null) located at 0x00661C1C is 36 bytes long.
memory check error at 0x00661C40 = 0x00, should be 0xFD.
DAMAGE: after (null) block (#16) at 0x00661C1C.
memory check error at 0x00661C8C = 0x00, should be 0xFD.
DAMAGE: after (null) block (#17) at 0x00661C68.

This is the birthday list:
   Pierre de Laplace was born on March 23, 1749.
   George Washington was born on February 11, 1732.
   Thomas Jefferson was born on April 13, 1743.
   Carl Friedrich Gauss was born on April 32, 1777.
   Ludwig van Beethoven was born on December 4, 1795.
Detected memory leaks!
Dumping objects ->
C:\DEV\EXAMPLE2.C(338) : {18} client block at 0x00661CB4, subtype 0, 36 bytes long:
   The birthday of Thomas Carlyle is 12/16/1770.
Object dump complete.

Log file output:

Memory Allocation Log File for Example Program, run at 14:11:01 on 04/28/95.
-----------------------------------------------------------------------------
Memory operation in C:\DEV\EXAMPLE2.C, line 327:
                                   allocating a 36-byte 'Client' block (# 13)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 14)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 15)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 16)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 17)
Memory operation in C:\DEV\EXAMPLE2.C, line 338:
                                    allocating a 36-byte 'Client' block (# 18)
Assert: C:\DEV\EXAMPLE2.C(219) : Assertion failed:
                                    ( bday->Day > 0 ) && ( bday->Day < 32 )
Warning: DAMAGE: after (null) block (#17) at 0x00661C68.
Warning: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661B38Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661B84Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661BD0Memory operation in (null), line 0:
                                    freeing a 0-byte 'Client' block (# 0)
 at 661C1CError: DAMAGE: after (null) block (#16) at 0x00661C1C.
Memory operation in (null), line 0: freeing a 0-byte 'Client' block (# 0)
 at 661C68Error: DAMAGE: after (null) block (#17) at 0x00661C68.

Debug Functions

See Also _malloc_dbg


_malloc_dbg

Allocates a block of memory in the heap with additional space for a debugging header and overwrite buffers (debug version only).

void *_malloc_dbg( size_t size, int blockType, const char *filename, int linenumber );

Routine | Required Header | Compatibility
_malloc_dbg | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

Upon successful completion, this function either returns a pointer to the user portion of the allocated memory block, calls the new handler function, or returns NULL. See the following Remarks section for a complete description of the return behavior. See the malloc function for more information on how the new handler function is used.

Parameters

size

Requested size of memory block (bytes)

blockType

Requested type of memory block: _CLIENT_BLOCK or _NORMAL_BLOCK

filename

Pointer to name of source file that requested allocation operation or NULL

linenumber

Line number in source file where allocation operation was requested or NULL

The filename and linenumber parameters are only available when _malloc_dbg has been called explicitly or the _CRTDBG_MAP_ALLOC preprocessor constant has been defined.

Remarks

_malloc_dbg is a debug version of the malloc function. When _DEBUG is not defined, calls to _malloc_dbg are removed during preprocessing. Both malloc and _malloc_dbg allocate a block of memory in the base heap, but _malloc_dbg offers several debugging features: buffers on either side of the user portion of the block to test for leaks, a block type parameter to track specific allocation types, and filename/linenumber information to determine the origin of allocation requests.

_malloc_dbg allocates the memory block with slightly more space than the requested size. The additional space is used by the debug heap manager to link the debug memory blocks together and to provide the application with debug header information and overwrite buffers. When the block is allocated, the user portion of the block is filled with the value 0xCD and each of the overwrite buffers are filled with 0xFD.

For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap. For information about the allocation block types and how they are used, see Types of Blocks on the Debug Heap. For information on the differences between calling a standard heap function versus its debug version in a debug build of an application, see Using the Debug Version Versus the Base Version.

Example

/*****************************************************************
 *  EXAMPLE  1                                                   *
 *  This simple program illustrates the basic debugging features *
 *  of the C runtime libraries, and the kind of debug output     *
 *  that these features generate.                                *
 *****************************************************************/

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

// This routine place comments at the head of a section of debug output
void OutputHeading( const char * explanation )
{
   _RPT1( _CRT_WARN, "\n\n%s:\n**************************************\
************************************\n", explanation );
}

// The following macros set and clear, respectively, given bits
// of the C runtime library debug flag, as specified by a bitmask.
#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#define  CLEAR_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag(~(a) & _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#define  CLEAR_CRT_DEBUG_FIELD(a) ((void) 0)
#endif

void main( )
{
   char *p1, *p2;
   _CrtMemState s1, s2, s3;

   // Send all reports to STDOUT
   _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
   _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_FILE );
   _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDOUT );

   // Allocate 2 memory blocks and store a string in each
   p1 = malloc( 34 );
   strcpy( p1, "This is the p1 string (34 bytes)." );

   p2 = malloc( 34 );
   strcpy( p2, "This is the p2 string (34 bytes)." );

   OutputHeading(
      "Use _ASSERTE to check that the two strings are identical" );
   _ASSERTE( strcmp( p1, p2 ) == 0 );

   OutputHeading(
      "Use a _RPT macro to report the string contents as a warning" );
   _RPT2( _CRT_WARN, "p1 points to '%s' and \np2 points to '%s'\n", p1, p2 );

   OutputHeading(
      "Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations" );
   _CrtMemDumpAllObjectsSince( NULL );

   free( p2 );

   OutputHeading(
      "Having freed p2, dump allocation information about p1 only" );
   _CrtMemDumpAllObjectsSince( NULL );

   // Store a memory checkpoint in the s1 memory-state structure
   _CrtMemCheckpoint( &s1 );

   // Allocate another block, pointed to by p2
   p2 = malloc( 38 );
   strcpy( p2, "This new p2 string occupies 38 bytes.");

   // Store a 2nd memory checkpoint in s2
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Dump the changes that occurred between two memory checkpoints" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   // Free p2 again and store a new memory checkpoint in s2
   free( p2 );
   _CrtMemCheckpoint( &s2 );

   OutputHeading(
      "Now the memory state at the two checkpoints is the same" );
   if ( _CrtMemDifference( &s3, &s1, &s2 ) )
      _CrtMemDumpStatistics( &s3 );

   strcpy( p1, "This new p1 string is over 34 bytes" );
   OutputHeading( "Free p1 after overwriting the end of the allocation" );
   free( p1 );

   // Set the debug-heap flag so that freed blocks are kept on the
   // linked list, to catch any inadvertent use of freed memory
   SET_CRT_DEBUG_FIELD( _CRTDBG_DELAY_FREE_MEM_DF );

   p1 = malloc( 10 );
   free( p1 );
   strcpy( p1, "Oops" );

   OutputHeading( "Perform a memory check after corrupting freed memory" );
   _CrtCheckMemory( );

   // Use explicit calls to _malloc_dbg to save file name and line number
   // information, and also to allocate Client type blocks for tracking
   p1 = _malloc_dbg( 40, _NORMAL_BLOCK, __FILE__, __LINE__ );
   p2 = _malloc_dbg( 40, _CLIENT_BLOCK, __FILE__, __LINE__ );
   strcpy( p1, "p1 points to a Normal allocation block" );
   strcpy( p2, "p2 points to a Client allocation block" );

   // You must use _free_dbg to free a Client block
   OutputHeading(
      "Using free( ) to free a Client block causes an assertion failure" );
   free( p1 );
   free( p2 );

   p1 = malloc( 10 );
   OutputHeading( "Examine outstanding allocations (dump memory leaks)" );
   _CrtDumpMemoryLeaks( );

   // Set the debug-heap flag so that memory leaks are reported when
   // the process terminates. Then, exit.
   OutputHeading( "Program exits without freeing a memory block" );
   SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

Output

Use _ASSERTE to check that the two strings are identical:
**************************************************************************
C:\DEV\EXAMPLE1.C(56) : Assertion failed: strcmp( p1, p2 ) == 0

Use a _RPT macro to report the string contents as a warning:
**************************************************************************
p1 points to 'This is the p1 string (34 bytes).' and
p2 points to 'This is the p2 string (34 bytes).'

Use _CRTMemDumpAllObjectsSince to check the p1 and p2 allocations:
**************************************************************************
Dumping objects ->
{13} normal block at 0x00660B5C, 34 bytes long
 Data: <This is the p2 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 32 20 73
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Having freed p2, dump allocation information about p1 only:
**************************************************************************
Dumping objects ->
{12} normal block at 0x00660B10, 34 bytes long
 Data: <This is the p1 s> 54 68 69 73 20 69 73 20 74 68 65 20 70 31 20 73
Object dump complete.

Dump the changes that occurred between two memory checkpoints:
**************************************************************************
0 bytes in 0 Free Blocks.
38 bytes in 1 Normal Blocks.
0 bytes in 0 CRT Blocks.
0 bytes in 0 IgnoreClient Blocks.
0 bytes in 0 (null) Blocks.
Largest number used: 4 bytes.
Total allocations: 38 bytes.

Now the memory state at the two checkpoints is the same:
**************************************************************************

Free p1 after overwriting the end of the allocation:
**************************************************************************
memory check error at 0x00660B32 = 0x73, should be 0xFD.
memory check error at 0x00660B33 = 0x00, should be 0xFD.
DAMAGE: after Normal block (#12) at 0x00660B10.

Perform a memory check after corrupting freed memory:
**************************************************************************
memory check error at 0x00660B10 = 0x4F, should be 0xDD.
memory check error at 0x00660B11 = 0x6F, should be 0xDD.
memory check error at 0x00660B12 = 0x70, should be 0xDD.
memory check error at 0x00660B13 = 0x73, should be 0xDD.
memory check error at 0x00660B14 = 0x00, should be 0xDD.
DAMAGE: on top of Free block at 0x00660B10.
DAMAGED located at 0x00660B10 is 10 bytes long.

Using free( ) to free a Client block causes an assertion failure:
**************************************************************************
dbgheap.c(1039) : Assertion failed: pHead->nBlockUse == nBlockUse

Examine outstanding allocations (dump memory leaks):
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Program exits without freeing a memory block:
**************************************************************************
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00660BE4, 10 bytes long
 Data: <          > CD CD CD CD CD CD CD CD CD CD
Object dump complete.

Debug Functions


_msize_dbg

Calculates the size of a block of memory in the heap (debug version only).

size_t _msize_dbg( void *userData, int blockType );

Routine | Required Header | Compatibility
_msize_dbg | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

Upon successful completion, _msize_dbg returns the size (bytes) of the specified memory block, otherwise it returns NULL.

Parameters

userData

Pointer to the memory block for which to determine the size

blockType

Type of the specified memory block: _CLIENT_BLOCK or _NORMAL_BLOCK

Remarks

_msize_dbg is a debug version of the _msize function. When _DEBUG is not defined, calls to _msize_dbg are removed during preprocessing. Both _msize and _msize_dbg calculate the size of a memory block in the base heap, but _msize_dbg adds two debugging features: It includes the buffers on either side of the user portion of the memory block in the returned size, and it allows size calculations for specific block types.

For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap. For information about the allocation block types and how they are used, see Types of Blocks on the Debug Heap. For information on the differences between calling a standard heap function versus its debug version in a debug build of an application, see Using the Debug Version Versus the Base Version.

Example

/*
 * REALLOCD.C
 * This program allocates a block of memory using _malloc_dbg
 * and then calls _msize_dbg to display the size of that block.
 * Next, it uses _realloc_dbg to expand the amount of
 * memory used by the buffer and then calls _msize_dbg again to
 * display the new amount of memory allocated to the buffer.
 */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <crtdbg.h>

void main( void )
{
        long *buffer;
        size_t size;

        /*
         * Call _malloc_dbg to include the filename and line number
         * of our allocation request in the header
         */
        buffer = (long *)_malloc_dbg( 40 * sizeof(long), _NORMAL_BLOCK, __FILE__, __LINE__ );
        if( buffer == NULL )
               exit( 1 );

        /*
         * Get the size of the buffer by calling _msize_dbg
         */
        size = _msize_dbg( buffer, _NORMAL_BLOCK );
        printf( "Size of block after _malloc_dbg of 40 longs: %u\n", size );

        /*
         * Reallocate the buffer using _realloc_dbg and show the new size
         */
        buffer = _realloc_dbg( buffer, size + (40 * sizeof(long)), _NORMAL_BLOCK, __FILE__, __LINE__ );
        if( buffer == NULL )
               exit( 1 );
        size = _msize_dbg( buffer, _NORMAL_BLOCK );
        printf( "Size of block after _realloc_dbg of 40 more longs: %u\n", size );

        free( buffer );
        exit( 0 );
}

Output

Size of block after _malloc_dbg of 40 longs: 160
Size of block after _realloc_dbg of 40 more longs: 320

Debug Functions

See Also _malloc_dbg


_realloc_dbg

Reallocates a specified block of memory in the heap by moving and/or resizing the block (debug version only).

void *_realloc_dbg( void *userData, size_t newSize, int blockType, const char *filename, int linenumber );

Routine | Required Header | Compatibility
_realloc_dbg | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Return Value

Upon successful completion, this function either returns a pointer to the user portion of the reallocated memory block, calls the new handler function, or returns NULL. See the following Remarks section for a complete description of the return behavior. See the realloc function for more information on how the new handler function is used.

Parameters

userData

Pointer to the previously allocated memory block

newSize

Requested size for reallocated block (bytes)

blockType

Requested type for reallocated block: _CLIENT_BLOCK or _NORMAL_BLOCK

filename

Pointer to name of source file that requested realloc operation or NULL

linenumber

Line number in source file where realloc operation was requested or NULL

The filename and linenumber parameters are only available when _realloc_dbg has been called explicitly or the _CRTDBG_MAP_ALLOC preprocessor constant has been defined.

Remarks

_realloc_dbg is a debug version of the realloc function. When _DEBUG is not defined, calls to _realloc_dbg are removed during preprocessing. Both realloc and _realloc_dbg reallocate a memory block in the base heap, but _realloc_dbg accommodates several debugging features: buffers on either side of the user portion of the block to test for leaks, a block type parameter to track specific allocation types, and filename/linenumber information to determine the origin of allocation requests.

_realloc_dbg reallocates the specified memory block with slightly more space than the requested newSize. newSize may be greater or less than the size of the originally allocated memory block. The additional space is used by the debug heap manager to link the debug memory blocks together and to provide the application with debug header information and overwrite buffers. The reallocation may result in moving the original memory block to a different location in the heap, as well as changing the size of the memory block. If the memory block is moved, the contents of the original block are copied over.

For information about how memory blocks are allocated, initialized, and managed in the debug version of the base heap, see Memory Management and the Debug Heap. For information about the allocation block types and how they are used, see Types of Blocks on the Debug Heap. For information on the differences between calling a standard heap function versus its debug version in a debug build of an application, see Using the Debug Version Versus the Base Version.

Example

/*
 * REALLOCD.C
 * This program allocates a block of memory using _malloc_dbg
 * and then calls _msize_dbg to display the size of that block.
 * Next, it uses _realloc_dbg to expand the amount of
 * memory used by the buffer and then calls _msize_dbg again to
 * display the new amount of memory allocated to the buffer.
 */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>
#include <crtdbg.h>

void main( void )
{
        long *buffer;
        size_t size;

        /*
         * Call _malloc_dbg to include the filename and line number
         * of our allocation request in the header
         */
        buffer = (long *)_malloc_dbg( 40 * sizeof(long), _NORMAL_BLOCK, __FILE__, __LINE__ );
        if( buffer == NULL )
               exit( 1 );

        /*
         * Get the size of the buffer by calling _msize_dbg
         */
        size = _msize_dbg( buffer, _NORMAL_BLOCK );
        printf( "Size of block after _malloc_dbg of 40 longs: %u\n", size );

        /*
         * Reallocate the buffer using _realloc_dbg and show the new size
         */
        buffer = _realloc_dbg( buffer, size + (40 * sizeof(long)), _NORMAL_BLOCK, __FILE__, __LINE__ );
        if( buffer == NULL )
               exit( 1 );
        size = _msize_dbg( buffer, _NORMAL_BLOCK );
        printf( "Size of block after _realloc_dbg of 40 more longs: %u\n", size );

        free( buffer );
        exit( 0 );
}

Output

Size of block after _malloc_dbg of 40 longs: 160
Size of block after _realloc_dbg of 40 more longs: 320

Debug Functions

See Also _malloc_dbg


_RPT, _RPTF Macros

Track an application’s progress by generating a debug report (debug version only).

_RPT0( reportType, format );

_RPT1( reportType, format, arg1 );

_RPT2( reportType, format, arg1, arg2 );

_RPT3( reportType, format, arg1, arg2, arg3 );

_RPT4( reportType, format, arg1, arg2, arg3, arg4 );

_RPTF0( reportType, format );

_RPTF1( reportType, format, arg1 );

_RPTF2( reportType, format, arg1, arg2 );

_RPTF3( reportType, format, arg1, arg2, arg3 );

_RPTF4( reportType, format, arg1, arg2, arg3, arg4 );

Macro | Required Header | Compatibility
_RPT macros | <crtdbg.h> | Win NT, Win 95
_RPTF macros | <crtdbg.h> | Win NT, Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBCMTD.LIB | Multithread static library, debug version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version

Although these are macros and are obtained by including CRTDBG.H, the application must link with one of the libraries listed above because these macros call other run-time functions.

Return Value

None

Parameters

reportType

Report type: _CRT_WARN, _CRT_ERROR, _CRT_ASSERT

format

Format-control string used to create the user message

arg1

Name of first substitution argument used by format

arg2

Name of second substitution argument used by format

arg3

Name of third substitution argument used by format

arg4

Name of fourth substitution argument used by format

All of these macros take the reportType and format parameters. In addition, they might also take arg1 through arg4, signified by the number appended to the macro name. For example, _RPT0 and _RPTF0 take no additional arguments, _RPT1 and _RPTF1 take arg1, _RPT2 and _RPTF2 take arg1 and arg2, and so on.

Remarks

The _RPT and _RPTF macros are similar to the printf function, as they can be used to track an application’s progress during the debugging process. However, these macros are more flexible than printf because they do not need to be enclosed in #ifdef statements to prevent them from being called in a retail build of an application. This flexibility is achieved by using the _DEBUG macro. The _RPT and _RPTF macros are only available when the _DEBUG flag is defined. When _DEBUG is not defined, calls to these macros are removed during preprocessing.

The _RPT macros call the _CrtDbgReport function to generate a debug report with a user message. The _RPTF macros create a debug report with the source file and line number where the report macro was called, in addition to the user message. The user message is created by substituting the arg[n] arguments into the format string, using the same rules defined by the printf function.

_CrtDbgReport generates the debug report and determines its destination(s), based on the current report modes and file defined for reportType. The _CrtSetReportMode and _CrtSetReportFile functions are used to define the destination(s) for each report type.

When the destination is a debug message window and the user chooses the Retry button, _CrtDbgReport returns 1, causing these macros to start the debugger, provided that “just-in-time” (JIT) debugging is enabled. For more information about using these macros as a debugging error handling mechanism, see Using Macros for Verification and Reporting.

Two other macros exist that generate a debug report. The _ASSERT macro generates a report, but only when its expression argument evaluates to FALSE. _ASSERTE is exactly like _ASSERT, but includes the failed expression in the generated report.

Example

/*
 * DBGMACRO.C
 * In this program, calls are made to the _ASSERT and _ASSERTE
 * macros to test the condition 'string1 == string2'.  If the
 * condition fails, these macros print a diagnostic message.
 * The _RPTn and _RPTFn group of macros are also exercised in
 * this program, as an alternative to the printf function.
 */

#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <crtdbg.h>

int main()
{
   char *p1, *p2;

   /*
    * The Reporting Mode and File must be specified
    * before generating a debug report via an assert
    * or report macro.
    * This program sends all report types to STDOUT
    */
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);

   /*
    * Allocate and assign the pointer variables
    */
   p1 = malloc(10);
   strcpy(p1, "I am p1");
   p2 = malloc(10);
   strcpy(p2, "I am p2");

   /*
    * Use the report macros as a debugging
    * warning mechanism, similar to printf.
    *
    * Use the assert macros to check if the
    * p1 and p2 variables are equivalent.
    *
    * If the expression fails, _ASSERTE will
    * include a string representation of the
    * failed expression in the report.
    * _ASSERT does not include the
    * expression in the generated report.
    */
   _RPT0(_CRT_WARN, "\n\n Use the assert macros to evaluate the expression p1 == p2.\n");
   _RPTF2(_CRT_WARN, "\n Will _ASSERT find '%s' == '%s' ?\n", p1, p2);
   _ASSERT(p1 == p2);

   _RPTF2(_CRT_WARN, "\n\n Will _ASSERTE find '%s' == '%s' ?\n", p1, p2);
   _ASSERTE(p1 == p2);

   _RPT2(_CRT_ERROR, "\n \n '%s' != '%s'\n", p1, p2);

   free(p2);
   free(p1);

   return 0;
}

Output

Use the assert macros to evaluate the expression p1 == p2.

dbgmacro.c(54) : Will _ASSERT find 'I am p1' == 'I am p2' ?
dbgmacro.c(55) : Assertion failed

dbgmacro.c(57) : Will _ASSERTE find 'I am p1' == 'I am p2' ?
dbgmacro.c(58) : Assertion failed: p1 == p2

'I am p1' != 'I am p2'

Debug Functions


_set_error_mode

_set_error_mode modifies __error_mode to determine a non-default location where the C runtime writes an error message for an error that will, possibly, end the program.

int _set_error_mode( int modeval );

Macro | Required Header | Compatibility
_set_error_mode | <stdlib.h> | ANSI, Win 95, Win NT

Libraries

LIBCD.LIB | Single thread static library, debug version
LIBC.LIB | Single thread static library, retail version
LIBCMTD.LIB | Multithread static library, debug version
LIBCMT.LIB | Multithread static library, retail version
MSVCRTD.LIB | Import library for MSVCRTD.DLL, debug version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Returns old setting or -1 if an error occurs.

Parameter

modeval

destination of error messages

Remarks

Control the error output sink by setting the value of __error_mode. Explicit controls are to direct output to standard error or to use the MessageBox API.

The modeval parameter can be set to one of the follow:

Parameter | Description
_OUT_TO_DEFAULT | error sink is determined by __app_type
_OUT_TO_STDERR | error sink is standard error
_OUT_TO_MSGBOX | error sink is a message box
_REPORT_ERRMODE | report the current __error_mode value

When used with an _ASSERT, _set_errror_mode will display the failed statement in the dialog box and give you the option of selecting Ignore, which allows you to continue executing the program.

Example

#include <stdlib.h>

#include <assert.h>

main()

{

_set_error_mode(_OUT_TO_MSGBOX);

assert(!"this is a test");

}


abort

Aborts the current process and returns an error code.

void abort( void );

Routine | Required Header | Compatibility
abort | <process.h> or <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

abort does not return control to the calling process. By default, it terminates the current process and returns an exit code of 3.

Remarks

The abort routine prints the message “abnormal program termination” and then calls raise(SIGABRT). The action taken in response to the SIGABRT signal depends on what action has been defined for that signal in a prior call to the signal function. The default SIGABRT action is for the calling process to terminate with exit code 3, returning control to the calling process or operating system. abort does not flush stream buffers or do atexit/_onexit processing.

abort determines the destination of the message based on the type of application that called the routine. Console applications always receive the message via stderr. In a single or multithreaded Windows application, abort calls the Windows MessageBox API to create a message box to display the message along with an OK button. When the user selects OK, the program aborts immediately.

When the application is linked with a debug version of the run-time libraries, abort creates a message box with three buttons: Abort, Retry, and Ignore. If the user selects Abort, the program aborts immediately. If the user selects Retry, the debugger is called and the user can debug the program if Just-In-Time (JIT) debugging is enabled. If the user selects Ignore, abort continues with its normal execution: creating the message box with the OK button. For more information, see Using C Run-Time Library Debugging Support.

Example

/* ABORT.C:  This program tries to open a
 * file and aborts if the attempt fails.
 */

#include  <stdio.h>
#include  <stdlib.h>

void main( void )
{
   FILE *stream;

   if( (stream = fopen( "NOSUCHF.ILE", "r" )) == NULL )
   {
      perror( "Couldn't open file" );
      abort();
   }
   else
      fclose( stream );
}

Output

Couldn't open file: No such file or directory

abnormal program termination

Process and Environment Control Routines

See Also _exec Function Overview, exit, raise, signal, _spawn Function Overview, _DEBUG


abs

Calculates the absolute value.

int abs( int n );

Routine | Required Header | Compatibility
abs | <stdlib.h> or <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The abs function returns the absolute value of its parameter. There is no error return.

Parameter

n

Integer value

Example

/* ABS.C: This program computes and displays
 * the absolute values of several numbers.
 */

#include  <stdio.h>
#include  <math.h>
#include  <stdlib.h>

void main( void )
{
   int    ix = -4, iy;
   long   lx = -41567L, ly;
   double dx = -3.141593, dy;

   iy = abs( ix );
   printf( "The absolute value of %d is %d\n", ix, iy);

   ly = labs( lx );
   printf( "The absolute value of %ld is %ld\n", lx, ly);

   dy = fabs( dx );
   printf( "The absolute value of %f is %f\n", dx, dy );
}

Output

The absolute value of -4 is 4
The absolute value of -41567 is 41567
The absolute value of -3.141593 is 3.141593

Data Conversion Routines | Floating-Point Support

See Also _cabs, fabs, labs


_access, _waccess

Determine file-access permission.

int _access( const char *path, int mode );

int _waccess( const wchar_t *path, int mode );

Routine | Required Header | Optional Headers | Compatibility
_access | <io.h> | <errno.h> | Win 95, Win NT
_waccess | <wchar.h> or <io.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if the file has the given mode. The function returns –1 if the named file does not exist or is not accessible in the given mode; in this case, errno is set as follows:

EACCES

Access denied: file’s permission setting does not allow specified access.

ENOENT

Filename or path not found.

Parameters

path

File or directory path

mode

Permission setting

Remarks

When used with files, the _access function determines whether the specified file exists and can be accessed as specified by the value of mode. When used with directories, _access determines only whether the specified directory exists; in Windows NT, all directories have read and write access.

mode Value | Checks File For
00 | Existence only
02 | Write permission
04 | Read permission
06 | Read and write permission

_waccess is a wide-character version of _access; the path argument to _waccess is a wide-character string. _waccess and _access behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_taccess | _access | _access | _waccess

Example

/* ACCESS.C: This example uses _access to check the
 * file named "ACCESS.C" to see if it exists and if
 * writing is allowed.
 */

#include  <io.h>
#include  <stdio.h>
#include  <stdlib.h>

void main( void )
{
   /* Check for existence */
   if( (_access( "ACCESS.C", 0 )) != -1 )
   {
      printf( "File ACCESS.C exists\n" );
      /* Check for write permission */
      if( (_access( "ACCESS.C", 2 )) != -1 )
         printf( "File ACCESS.C has write permission\n" );
   }
}

Output

File ACCESS.C exists
File ACCESS.C has write permission

File Handling Routines

See Also _chmod, _fstat, _open, _stat


acos

Calculates the arccosine.

double acos( double x );

Routine | Required Header | Optional Headers | Compatibility
acos | <math.h> | <errno.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The acos function returns the arccosine of x in the range 0 to π radians. If x is less than –1 or greater than 1, acos returns an indefinite (same as a quiet NaN). You can modify error handling with the _matherr routine.

Parameter

x

Value between –1 and 1 whose arccosine is to be calculated

Example

/* ASINCOS.C: This program prompts for a value in the range
 * -1 to 1. Input values outside this range will produce
 * _DOMAIN error messages.If a valid value is entered, the
 * program prints the arcsine and the arccosine of that value.
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void main( void )
{
   double x, y;

   printf( "Enter a real number between -1 and 1: " );
   scanf( "%lf", &x );
   y = asin( x );
   printf( "Arcsine of %f = %f\n", x, y );
   y = acos( x );
   printf( "Arccosine of %f = %f\n", x, y );
}

Output

Enter a real number between -1 and 1: .32696
Arcsine of 0.326960 = 0.333085
Arccosine of 0.326960 = 1.237711

Floating-Point Support Routines

See Also asin, atan, cos, _matherr, sin, tan


_alloca

Allocates memory on the stack.

void *_alloca( size_t size );

Routine | Required Header | Compatibility
_alloca | <malloc.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The _alloca routine returns a void pointer to the allocated space, which is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than char, use a type cast on the return value. A stack overflow exception is generated if the space cannot be allocated.

Parameter

size

Bytes to be allocated from stack

Remarks

_alloca allocates size bytes from the program stack. The allocated space is automatically freed when the calling function exits. Therefore, do not pass the pointer value returned by _alloca as an argument to free.

There are restrictions to explicitly calling _alloca in an exception handler (EH). EH routines that run on x86-class processors operate in their own memory “frame”: They perform their tasks in memory space that is not based on the current location of the stack pointer of the enclosing function. The most common implementations include Windows NT structured exception handling (SEH) and C++ catch clause expressions. Therefore, explicitly calling _alloca in any of the following scenarios results in program failure during the return to the calling EH routine:

  • Windows NT SEH exception filter expression: __except ( alloca() )

  • Windows NT SEH final exception handler: __finally { alloca() }

  • C++ EH catch clause expression

However, _alloca can be called directly from within an EH routine or from an application-supplied callback that gets invoked by one of the EH scenarios listed above.

Memory Allocation Routines

See Also calloc, malloc, realloc


asctime, _wasctime

Converts a tm time structure to a character string.

char *asctime( const struct tm *timeptr );

wchar_t *_wasctime( const struct tm *timeptr );

Routine | Required Header | Compatibility
asctime | <time.h> | ANSI, Win 95, Win NT
_wasctime | <time.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

asctime returns a pointer to the character string result; _wasctime returns a pointer to the wide-character string result. There is no error return value.

Parameter

timeptr

Time/date structure

Remarks

The asctime function converts a time stored as a structure to a character string. The timeptr value is usually obtained from a call to gmtime or localtime, which both return a pointer to a tm structure, defined in TIME.H.

timeptr Field | Value
tm_hour | Hours since midnight (0 – 23)
tm_isdst | Positive if daylight saving time is in effect; 0 if daylight saving time is not in effect; negative if status of daylight saving time is unknown. The C run-time library assumes the United States’s rules for implementing the calculation of Daylight Saving Time (DST).
tm_mday | Day of month (1 – 31)
tm_min | Minutes after hour (0 – 59)
tm_mon | Month (0 – 11; January = 0)
tm_sec | Seconds after minute (0 – 59)
tm_wday | Day of week (0 – 6; Sunday = 0)
tm_yday | Day of year (0 – 365; January 1 = 0)
tm_year | Year (current year minus 1900)

The converted character string is also adjusted according to the local time zone settings. See the time, _ftime, and localtime functions for information on configuring the local time and the _tzset function for details about defining the time zone environment and global variables.

The string result produced by asctime contains exactly 26 characters and has the form Wed Jan 02 02:03:55 1980\n\0. A 24-hour clock is used. All fields have a constant width. The newline character and the null character occupy the last two positions of the string. asctime uses a single, statically allocated buffer to hold the return string. Each call to this function destroys the result of the previous call.

_wasctime is a wide-character version of asctime. _wasctime and asctime behave identically otherwise.

Generic-Text Routine Mapping:

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tasctime | asctime | asctime | _wasctime

Example

/* ASCTIME.C: This program places the system time
 * in the long integer aclock, translates it into the
 * structure newtime and then converts it to string
 * form for output, using the asctime function.
 */

#include <time.h>
#include <stdio.h>

struct tm *newtime;
time_t aclock;

void main( void )
{
   time( &aclock );                 /* Get time in seconds */

   newtime = localtime( &aclock );  /* Convert time to struct */
                                    /* tm form */

   /* Print local time as a string */
   printf( "The current date and time are: %s", asctime( newtime ) );
}

Output

The current date and time are: Sun May 01 20:27:01 1994

Time Management Routines

See Also ctime, _ftime, gmtime, localtime, time, _ tzset


asin

Calculates the arcsine.

double asin( double x );

Routine | Required Header | Compatibility
asin | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The asin function returns the arcsine of x in the range –π/2 to π/2 radians. If x is less than –1 or greater than 1, asin returns an indefinite (same as a quiet NaN). You can modify error handling with the _matherr routine.

Parameter

x

Value whose arcsine is to be calculated

Example

/* ASINCOS.C: This program prompts for a value in the range
 * -1 to 1. Input values outside this range will produce
 * _DOMAIN error messages.If a valid value is entered, the
 * program prints the arcsine and the arccosine of that value.
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

void main( void )
{
   double x, y;

   printf( "Enter a real number between -1 and 1: " );
   scanf( "%lf", &x );
   y = asin( x );
   printf( "Arcsine of %f = %f\n", x, y );
   y = acos( x );
   printf( "Arccosine of %f = %f\n", x, y );
}

Output

Enter a real number between -1 and 1: .32696
Arcsine of 0.326960 = 0.333085
Arccosine of 0.326960 = 1.237711

Floating-Point Support Routines

See Also acos, atan, cos, _matherr, sin, tan


assert

Evaluates an expression and when the result is FALSE, prints a diagnostic message and aborts the program.

void assert( int expression );

Routine | Required Header | Compatibility
assert | <assert.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

expression

Expression (including pointers) that evaluates to nonzero or 0

Remarks

The ANSI assert macro is typically used to identify logic errors during program development, by implementing the expression argument to evaluate to false only when the program is operating incorrectly. After debugging is complete, assertion checking can be turned off without modifying the source file by defining the identifier NDEBUG. NDEBUG can be defined with a /D command-line option or with a #define directive. If NDEBUG is defined with #define, the directive must appear before ASSERT.H is included.

assert prints a diagnostic message when expression evaluates to false (0) and calls abort to terminate program execution. No action is taken if expression is true (nonzero). The diagnostic message includes the failed expression and the name of the source file and line number where the assertion failed.

The destination of the diagnostic message depends on the type of application that called the routine. Console applications always receive the message via stderr. In a single- or multithreaded Windows application, assert calls the Windows MessageBox API to create a message box to display the message along with an OK button. When the user chooses OK, the program aborts immediately.

When the application is linked with a debug version of the run-time libraries, assert creates a message box with three buttons: Abort, Retry, and Ignore. If the user selects Abort, the program aborts immediately. If the user selects Retry, the debugger is called and the user can debug the program if Just-In-Time (JIT) debugging is enabled. If the user selects Ignore, assert continues with its normal execution: creating the message box with the OK button. Note that choosing Ignore when an error condition exists can result in “undefined behavior.” For more information, see Using C Run-Time Library Debugging Support.

The assert routine is available in both the release and debug versions of the C run-time libraries. Two other assertion macros, _ASSERT and _ASSERTE, are also available, but they only evaluate the expressiosn passed to them when the _DEBUG flag has been defined.

Example

/* ASSERT.C: In this program, the analyze_string function uses
 * the assert function to test several conditions related to
 * string and length. If any of the conditions fails, the program
 * prints a message indicating what caused the failure.
 */

#include <stdio.h>
#include <assert.h>
#include <string.h>

void analyze_string( char *string );   /* Prototype */

void main( void )
{
   char  test1[] = "abc", *test2 = NULL, test3[] = "";

   printf ( "Analyzing string '%s'\n", test1 );
   analyze_string( test1 );
   printf ( "Analyzing string '%s'\n", test2 );
   analyze_string( test2 );
   printf ( "Analyzing string '%s'\n", test3 );
   analyze_string( test3 );
}

/* Tests a string to see if it is NULL, */
/*   empty, or longer than 0 characters */
void analyze_string( char * string )
{
   assert( string != NULL );        /* Cannot be NULL */
   assert( *string != '\0' );       /* Cannot be empty */
   assert( strlen( string ) > 2 );  /* Length must exceed 2 */
}

Output

Analyzing string 'abc'
Analyzing string '(null)'
Assertion failed: string != NULL, file assert.c, line 24

abnormal program termination

Error Handling Routines | Process and Environment Control Routines

See Also abort, raise, signal, _ASSERT, _ASSERTE, _DEBUG


atan, atan2

Calculates the arctangent of x (atan) or the arctangent of y/x (atan2).

double atan( double x );

double atan2( double y, double x );

Routine | Required Header | Compatibility
atan | <math.h> | ANSI, Win 95, Win NT
atan2 | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

atan returns the arctangent of x. atan2 returns the arctangent of y/x. If x is 0, atan returns 0. If both parameters of atan2 are 0, the function returns 0. You can modify error handling by using the _matherr routine. atan returns a value in the range –π/2 to π/2 radians; atan2 returns a value in the range –π to π radians, using the signs of both parameters to determine the quadrant of the return value.

Parameters

x, y

Any numbers

Remarks

The atan function calculates the arctangent of x. atan2 calculates the arctangent of y/x. atan2 is well defined for every point other than the origin, even if x equals 0 and y does not equal 0.

Example

/* ATAN.C: This program calculates
 * the arctangent of 1 and -1.
 */

#include <math.h>
#include <stdio.h>
#include <errno.h>

void main( void )
{
   double x1, x2, y;

   printf( "Enter a real number: " );
   scanf( "%lf", &x1 );
   y = atan( x1 );
   printf( "Arctangent of %f: %f\n", x1, y );
   printf( "Enter a second real number: " );
   scanf( "%lf", &x2 );
   y = atan2( x1, x2 );
   printf( "Arctangent of %f / %f: %f\n", x1, x2, y );
}

Output

Enter a real number: -862.42
Arctangent of -862.420000: -1.569637
Enter a second real number: 78.5149
Arctangent of -862.420000 / 78.514900: -1.480006

Floating-Point Support Routines

See Also acos, asin, cos, _matherr, sin, tan


atexit

Processes the specified function at exit.

int atexit( void ( __cdecl *func )( void ) );

Routine | Required Header | Compatibility
atexit | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

To generate an ANSI-compliant application, use the ANSI-standard atexit function (rather than the similar _onexit function).

Return Value

atexit returns 0 if successful, or a nonzero value if an error occurs.

Parameter

func

Function to be called

Remarks

The atexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to atexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to atexit cannot take parameters. atexit and _onexit use the heap to hold the register of functions. Thus, the number of functions that can be registered is limited only by heap memory.

Example

/* ATEXIT.C: This program pushes four functions onto
 * the stack of functions to be executed when atexit
 * is called. When the program exits, these programs
 * are executed on a "last in, first out" basis.
 */

#include <stdlib.h>
#include <stdio.h>

void fn1( void ), fn2( void ), fn3( void ), fn4( void );

void main( void )
{
   atexit( fn1 );
   atexit( fn2 );
   atexit( fn3 );
   atexit( fn4 );
   printf( "This is executed first.\n" );
}

void fn1()
{
   printf( "next.\n" );
}

void fn2()
{
   printf( "executed " );
}

void fn3()
{
   printf( "is " );
}

void fn4()
{
   printf( "This " );
}

Output

This is executed first.
This is executed next.

Process and Environment Control Routines

See Also abort, exit, _onexit


atof, atoi, _atoi64, atol

Convert strings to double (atof), integer (atoi, _atoi64), or long (atol).

double atof( const char *string );

int atoi( const char *string );

__int64 _atoi64( const char *string );

long atol( const char *string );

Routine | Required Header | Compatibility
atof | <math.h> and <stdlib.h> | ANSI, Win 95, Win NT
atoi | <stdlib.h> | ANSI, Win 95, Win NT
_atoi64 | <stdlib.h> | Win 95, Win NT
atol | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each function returns the double, int, __int64 or long value produced by interpreting the input characters as a number. The return value is 0 (for atoi and _atoi64), 0L (for atol), or 0.0 (for atof) if the input cannot be converted to a value of that type. The return value is undefined in case of overflow.

Parameter

string

String to be converted

Remarks

These functions convert a character string to a double-precision floating-point value (atof), an integer value (atoi and _atoi64), or a long integer value (atol). The input string is a sequence of characters that can be interpreted as a numerical value of the specified type. The output value is affected by the setting of the LC_NUMERIC category in the current locale. For more information on the LC_NUMERIC category, see setlocale. The longest string size that atof can handle is 100 characters. The function stops reading the input string at the first character that it cannot recognize as part of a number. This character may be the null character ('\0') terminating the string.

The string argument to atof has the following form:

[whitespace] [sign] [digits] [.digits] [ {d | D | e | E }[sign]digits]

A whitespace consists of space and/or tab characters, which are ignored; sign is either plus (+) or minus ( – ); and digits are one or more decimal digits. If no digits appear before the decimal point, at least one must appear after the decimal point. The decimal digits may be followed by an exponent, which consists of an introductory letter ( d, D, e, or E) and an optionally signed decimal integer.

atoi, _atoi64, and atol do not recognize decimal points or exponents. The string argument for these functions has the form:

[whitespace] [sign]digits

where whitespace, sign, and digits are exactly as described above for atof.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_ttoi | atoi | atoi | _wtoi
_ttol | atol | atol | _wtol

Example

/* ATOF.C: This program shows how numbers stored
 * as strings can be converted to numeric values
 * using the atof, atoi, and atol functions.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char *s; double x; int i; long l;

   s = "  -2309.12E-15";    /* Test of atof */
   x = atof( s );
   printf( "atof test: ASCII string: %s\tfloat:  %e\n", s, x );

   s = "7.8912654773d210";  /* Test of atof */
   x = atof( s );
   printf( "atof test: ASCII string: %s\tfloat:  %e\n", s, x );

   s = "  -9885 pigs";      /* Test of atoi */
   i = atoi( s );
   printf( "atoi test: ASCII string: %s\t\tinteger: %d\n", s, i );

   s = "98854 dollars";     /* Test of atol */
   l = atol( s );
   printf( "atol test: ASCII string: %s\t\tlong: %ld\n", s, l );
}

Output

atof test: ASCII string:   -2309.12E-15   float:  -2.309120e-012
atof test: ASCII string: 7.8912654773d210   float:  7.891265e+210
atoi test: ASCII string:   -9885 pigs      integer: -9885
atol test: ASCII string: 98854 dollars      long: 98854

Data Conversion Routines | Floating-Point Support Routines | Locale Routines

See Also _ecvt, _fcvt, _gcvt, setlocale, strtod, wcstol, strtoul


_beginthread, _beginthreadex

Create a thread.

unsigned long _beginthread( void( __cdecl *start_address )( void * ), unsigned stack_size, void *arglist );

unsigned long _beginthreadex( void *security, unsigned stack_size, unsigned ( __stdcall *start_address )( void * ), void *arglist, unsigned initflag, unsigned *thrdaddr );

Routine | Required Header | Compatibility
_beginthread | <process.h> | Win 95, Win NT
_beginthreadex | <process.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

To use _beginthread or _beginthreadex, the application must link with one of the multithreaded C run-time libraries.

Return Value

If successful, each of these functions returns a handle to the newly created thread. _beginthread returns –1 on an error, in which case errno is set to EAGAIN if there are too many threads, or to EINVAL if the argument is invalid or the stack size is incorrect. _beginthreadex returns 0 on an error, in which case errno and doserrno are set.

Parameters

start_address

Start address of routine that begins execution of new thread

stack_size

Stack size for new thread or 0

arglist

Argument list to be passed to new thread or NULL

security

Security descriptor for new thread; must be NULL for Windows 95 applications

initflag

Initial state of new thread (0 for running or CREATE_SUSPEND for suspended)

thrdaddr

Points to a 32-bit variable that receives the thread identifier

Remarks

The _beginthread function creates a thread that begins execution of a routine at start_address. The routine at start_address must use the __cdecl calling convention and should have no return value. When the thread returns from that routine, it is terminated automatically.

_beginthreadex resembles the Win32 CreateThread API more closely than does _beginthread. _beginthreadex differs from _beginthread in the following ways:

  • _beginthreadex has three additional parameters: initflag, security, threadaddr. The new thread can be created in a suspended state, with a specified security (Windows NT only), and can be accessed using thrdaddr, which is the thread identifier.

  • The routine at start_address passed to _beginthreadex must use the __stdcall calling convention and must return a thread exit code.

  • _beginthreadex returns 0 on failure, rather than –1.

  • A thread created with _beginthreadex is terminated by a call to _endthreadex.

You can call _endthread or _endthreadex explicitly to terminate a thread; however, _endthread or _endthreadex is called automatically when the thread returns from the routine passed as a parameter. Terminating a thread with a call to endthread or _endthreadex helps to ensure proper recovery of resources allocated for the thread.

_endthread automatically closes the thread handle (whereas _endthreadex does not). Therefore, when using _beginthread and _endthread, do not explicitly close the thread handle by calling the Win32 CloseHandle API. This behavior differs from the Win32 ExitThread API.

Note For an executable file linked with LIBCMT.LIB, do not call the Win32 ExitThread API; this prevents the run-time system from reclaiming allocated resources. _endthread and _endthreadex reclaim allocated thread resources and then call ExitThread.

The operating system handles the allocation of the stack when either _beginthread or _beginthreadex is called; you do not need to pass the address of the thread stack to either of these functions. In addition, the stack_size argument can be 0, in which case the operating system uses the same value as the stack specified for the main thread.

arglist is a parameter to be passed to the newly created thread. Typically it is the address of a data item, such as a character string. arglist may be NULL if it is not needed, but _beginthread and _beginthreadex must be provided with some value to pass to the new thread. All threads are terminated if any thread calls abort, exit, _exit, or ExitProcess.

Example

/* BEGTHRD.C illustrates multiple threads using functions:
 *
 *      _beginthread            _endthread
 *
 *
 * This program requires the multithreaded library. For example,
 * compile with the following command line:
 *     CL /MT /D "_X86_" BEGTHRD.C
 *
 * If you are using the Visual C++ development environment, select the
 * Multi-Threaded runtime library in the compiler Project Settings
 * dialog box.
 *
 */

#include <windows.h>
#include <process.h>    /* _beginthread, _endthread */
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>

void Bounce( void *ch );
void CheckKey( void *dummy );

/* GetRandom returns a random integer between min and max. */
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

BOOL repeat = TRUE;     /* Global repeat flag and video variable */
HANDLE hStdOut;         /* Handle for console window */
CONSOLE_SCREEN_BUFFER_INFO csbi;    /* Console information structure */

void main()
{
    CHAR    ch = 'A';

    hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

    /* Get display screen's text row and column information. */
   GetConsoleScreenBufferInfo( hStdOut, &csbi );

    /* Launch CheckKey thread to check for terminating keystroke. */
    _beginthread( CheckKey, 0, NULL );

    /* Loop until CheckKey terminates program. */
    while( repeat )
    {
        /* On first loops, launch character threads. */
        _beginthread( Bounce, 0, (void *) (ch++)  );

        /* Wait one second between loops. */
        Sleep( 1000L );
    }
}

/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */
void CheckKey( void *dummy )
{
    _getch();
    repeat = 0;    /* _endthread implied */

}

/* Bounce - Thread to create and and control a colored letter that moves
 * around on the screen.
 *
 * Params: ch - the letter to be moved
 */
void Bounce( void *ch )
{
    /* Generate letter and color attribute from thread argument. */
    char    blankcell = 0x20;
    char    blockcell = (char) ch;
    BOOL    first = TRUE;
   COORD   oldcoord, newcoord;
   DWORD   result;

    /* Seed random number generator and get initial location. */
    srand( _threadid );
    newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );
    newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );
    while( repeat )
    {
        /* Pause between loops. */
        Sleep( 100L );

        /* Blank out our old position on the screen, and draw new letter. */
        if( first )
            first = FALSE;
        else
         WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );
         WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );

        /* Increment the coordinate for next placement of the block. */
        oldcoord.X = newcoord.X;
        oldcoord.Y = newcoord.Y;
        newcoord.X += GetRandom( -1, 1 );
        newcoord.Y += GetRandom( -1, 1 );

        /* Correct placement (and beep) if about to go off the screen. */
        if( newcoord.X < 0 )
            newcoord.X = 1;
        else if( newcoord.X == csbi.dwSize.X )
            newcoord.X = csbi.dwSize.X - 2;
        else if( newcoord.Y < 0 )
            newcoord.Y = 1;
        else if( newcoord.Y == csbi.dwSize.Y )
            newcoord.Y = csbi.dwSize.Y - 2;

        /* If not at a screen border, continue, otherwise beep. */
        else
            continue;
        Beep( ((char) ch - 'A') * 100, 175 );
    }
    /* _endthread given to terminate */
    _endthread();
}

Process and Environment Control Routines

See Also _endthread, abort, exit


Bessel Functions

The Bessel functions are commonly used in the mathematics of electromagnetic wave theory.

_j0, _j1, _jn

These routines return Bessel functions of the first kind: orders 0, 1, and n, respectively.

_y0, _y1, _yn

These routines return Bessel functions of the second kind: orders 0, 1, and n, respectively.

Example

/* BESSEL.C: This program illustrates Bessel functions,
 * including:    _j0   _j1   _jn   _y0   _y1   _yn
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.387;
   int n = 3, c;

   printf( "Bessel functions for x = %f:\n", x );
   printf( " Kind\t\tOrder\tFunction\tResult\n\n" );
   printf( " First\t\t0\t_j0( x )\t%f\n", _j0( x ) );
   printf( " First\t\t1\t_j1( x )\t%f\n", _j1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " First\t\t%d\t_jn( n, x )\t%f\n", c, _jn( c, x ) );
   printf( " Second\t0\t_y0( x )\t%f\n", _y0( x ) );
   printf( " Second\t1\t_y1( x )\t%f\n", _y1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " Second\t%d\t_yn( n, x )\t%f\n", c, _yn( c, x ) );
}

Output

Bessel functions for x = 2.387000:
  Kind      Order   Function   Result

  First      0   _j0( x )   0.009288
  First      1   _j1( x )   0.522941
  First      2   _jn( n, x )   0.428870
  First      3   _jn( n, x )   0.195734
  First      4   _jn( n, x )   0.063131
  Second   0   _y0( x )   0.511681
  Second   1   _y1( x )   0.094374
  Second   2   _yn( n, x )   -0.432608
  Second   3   _yn( n, x )   -0.819314
  Second   4   _yn( n, x )   -1.626833

Floating-Point Support Routines

See Also _matherr


Bessel Functions: _j0, _j1, _jn

Compute the Bessel function.

double _j0( double x );

double _j1( double x );

double _jn( int n, double x );

Routine | Required Header | Compatibility
_j0 | <math.h> | Win 95, Win NT
_j1 | <math.h> | Win 95, Win NT
_jn | <math.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a Bessel function of x. You can modify error handling by using _matherr.

Parameters

x

Floating-point value

n

Integer order of Bessel function

Remarks

The _j0, _j1, and _jn routines return Bessel functions of the first kind: orders 0, 1, and n, respectively.

Example

/* BESSEL.C: This program illustrates Bessel functions,
 * including:    _j0   _j1   _jn   _y0   _y1   _yn
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.387;
   int n = 3, c;

   printf( "Bessel functions for x = %f:\n", x );
   printf( " Kind\t\tOrder\tFunction\tResult\n\n" );
   printf( " First\t\t0\t_j0( x )\t%f\n", _j0( x ) );
   printf( " First\t\t1\t_j1( x )\t%f\n", _j1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " First\t\t%d\t_jn( n, x )\t%f\n", c, _jn( c, x ) );
   printf( " Second\t0\t_y0( x )\t%f\n", _y0( x ) );
   printf( " Second\t1\t_y1( x )\t%f\n", _y1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " Second\t%d\t_yn( n, x )\t%f\n", c, _yn( c, x ) );
}

Output

Bessel functions for x = 2.387000:
  Kind      Order   Function   Result

  First      0   _j0( x )   0.009288
  First      1   _j1( x )   0.522941
  First      2   _jn( n, x )   0.428870
  First      3   _jn( n, x )   0.195734
  First      4   _jn( n, x )   0.063131
  Second   0   _y0( x )   0.511681
  Second   1   _y1( x )   0.094374
  Second   2   _yn( n, x )   -0.432608
  Second   3   _yn( n, x )   -0.819314
  Second   4   _yn( n, x )   -1.626833

Floating-Point Support Routines | Bessel Functions

See Also _matherr


Bessel Functions: _y0, _y1, _yn

Compute the Bessel function.

double _y0( double x );

double _y1( double x );

double _yn( int n, double x );

Routine | Required Header | Compatibility
_y0 | <math.h> | Win 95, Win NT
_y1 | <math.h> | Win 95, Win NT
_yn | <math.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a Bessel function of x. If x is negative, the routine sets errno to EDOM, prints a _DOMAIN error message to stderr, and returns _HUGE_VAL. You can modify error handling by using _matherr.

Parameters

x

Floating-point value

n

Integer order of Bessel function

Remarks

The _y0, _y1, and _yn routines return Bessel functions of the second kind: orders 0, 1, and n, respectively.

Example

/* BESSEL.C: This program illustrates Bessel functions,
 * including:    _j0   _j1   _jn   _y0   _y1   _yn
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.387;
   int n = 3, c;

   printf( "Bessel functions for x = %f:\n", x );
   printf( " Kind\t\tOrder\tFunction\tResult\n\n" );
   printf( " First\t\t0\t_j0( x )\t%f\n", _j0( x ) );
   printf( " First\t\t1\t_j1( x )\t%f\n", _j1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " First\t\t%d\t_jn( n, x )\t%f\n", c, _jn( c, x ) );
   printf( " Second\t0\t_y0( x )\t%f\n", _y0( x ) );
   printf( " Second\t1\t_y1( x )\t%f\n", _y1( x ) );
   for( c = 2; c < 5; c++ )
      printf( " Second\t%d\t_yn( n, x )\t%f\n", c, _yn( c, x ) );
}

Output

Bessel functions for x = 2.387000:
  Kind      Order   Function   Result

  First      0   _j0( x )   0.009288
  First      1   _j1( x )   0.522941
  First      2   _jn( n, x )   0.428870
  First      3   _jn( n, x )   0.195734
  First      4   _jn( n, x )   0.063131
  Second   0   _y0( x )   0.511681
  Second   1   _y1( x )   0.094374
  Second   2   _yn( n, x )   -0.432608
  Second   3   _yn( n, x )   -0.819314
  Second   4   _yn( n, x )   -1.626833

Floating-Point Support Routines | Bessel Functions

See Also _matherr


bsearch

Performs a binary search of a sorted array.

void *bsearch( const void *key, const void *base, size_t num, size_t width, int ( __cdecl *compare ) ( const void *elem1, const void *elem2 ) );

Routine | Required Header | Compatibility
bsearch | <stdlib.h> and <search.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

bsearch returns a pointer to an occurrence of key in the array pointed to by base. If key is not found, the function returns NULL. If the array is not in ascending sort order or contains duplicate records with identical keys, the result is unpredictable.

Parameters

key

Object to search for

base

Pointer to base of search data

num

Number of elements

width

Width of elements

compare

Function that compares two elements: elem1 and elem2

elem1

Pointer to the key for the search

elem2

Pointer to the array element to be compared with the key

Remarks

The bsearch function performs a binary search of a sorted array of num elements, each of width bytes in size. The base value is a pointer to the base of the array to be searched, and key is the value being sought. The compare parameter is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. bsearch calls the compare routine one or more times during the search, passing pointers to two array elements on each call. The compare routine compares the elements, then returns one of the following values:

Value Returned by compare Routine | Description
< 0 | elem1 less than elem2
0 | elem1 equal to elem2
> 0 | elem1 greater than elem2

Example

/* BSEARCH.C: This program reads the command-line
 * parameters, sorting them with qsort, and then
 * uses bsearch to find the word "cat."
 */

#include <search.h>
#include <string.h>
#include <stdio.h>

int compare( char **arg1, char **arg2 ); /* Declare a function for compare */

void main( int argc, char **argv )
{
   char **result;
   char *key = "cat";
   int i;

   /* Sort using Quicksort algorithm: */
   qsort( (void *)argv, (size_t)argc, sizeof( char * ), (int (*)(const
   void*, const void*))compare );

   for( i = 0; i < argc; ++i )    /* Output sorted list */
      printf( "%s ", argv[i] );

   /* Find the word "cat" using a binary search algorithm: */
   result = (char **)bsearch( (char *) &key, (char *)argv, argc,
                              sizeof( char * ), (int (*)(const void*, const void*))compare );
   if( result )
      printf( "\n%s found at %Fp\n", *result, result );
   else
      printf( "\nCat not found!\n" );
}

int compare( char **arg1, char **arg2 )
{
   /* Compare all of both strings: */
   return _strcmpi( *arg1, *arg2 );
}

Output

[C:\work]bsearch dog pig horse cat human rat cow goat
bsearch cat cow dog goat horse human pig rat
cat found at 002D0008

Searching and Sorting Routines

See Also _lfind, _lsearch, qsort


_cabs

Calculates the absolute value of a complex number.

double _cabs( struct _complex z );

Routine | Required Header | Compatibility
_cabs | <math.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_cabs returns the absolute value of its argument if successful. On overflow _cabs returns HUGE_VAL and sets errno to ERANGE. You can change error handling with _matherr.

Parameter

z

Complex number

Remarks

The _cabs function calculates the absolute value of a complex number, which must be a structure of type _complex. The structure z is composed of a real component x and an imaginary component y. A call to _cabs produces a value equivalent to that of the expression sqrt( z.x*z.x + z.y*z.y ).

Example

/* CABS.C: Using _cabs, this program calculates
 * the absolute value of a complex number.
 */
#include <math.h>
#include <stdio.h>

void main( void )
{
   struct _complex number = { 3.0, 4.0 };
   double d;

   d = _cabs( number );
   printf( "The absolute value of %f + %fi is %f\n",
           number.x, number.y, d );
}

Output
The absolute value of 3.000000 + 4.000000i is 5.000000

Floating-Point Support Routines

See Also abs, fabs, labs


calloc

Allocates an array in memory with elements initialized to 0.

void *calloc( size_t num, size_t size );

Routine | Required Header | Compatibility
calloc | <stdlib.h> and <malloc.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

calloc returns a pointer to the allocated space. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

Parameters

num

Number of elements

size

Length in bytes of each element

Remarks

The calloc function allocates storage space for an array of num elements, each of length size bytes. Each element is initialized to 0.

calloc calls malloc in order to use the C++ _set_new_mode function to set the new handler mode. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when calloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. To override the default, call

_set_new_mode(1)

early in your program, or link with NEWMODE.OBJ.

When the application is linked with a debug version of the C run-time libraries, calloc resolves to _calloc_dbg. For more information about how the heap is managed during the debugging process, see Using C Run-Time Library Debugging Support.

Example

/* CALLOC.C: This program uses calloc to allocate space for
 * 40 long integers. It initializes each element to zero.
 */
#include <stdio.h>
#include <malloc.h>

void main( void )
{
   long *buffer;

   buffer = (long *)calloc( 40, sizeof( long ) );
   if( buffer != NULL )
      printf( "Allocated 40 long integers\n" );
   else
      printf( "Can't allocate memory\n" );
   free( buffer );
}

Output
Allocated 40 long integers

Memory Allocation Routines

See Also free, malloc, realloc


ceil

Calculates the ceiling of a value.

double ceil( double x );

Routine | Required Header | Compatibility
ceil | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The ceil function returns a double value representing the smallest integer that is greater than or equal to x. There is no error return.

Parameter

x

Floating-point value

Example

/* FLOOR.C: This example displays the largest integers
 * less than or equal to the floating-point values 2.8
 * and -2.8. It then shows the smallest integers greater
 * than or equal to 2.8 and -2.8.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double y;

   y = floor( 2.8 );
   printf( "The floor of 2.8 is %f\n", y );
   y = floor( -2.8 );
   printf( "The floor of -2.8 is %f\n", y );

   y = ceil( 2.8 );
   printf( "The ceil of 2.8 is %f\n", y );
   y = ceil( -2.8 );
   printf( "The ceil of -2.8 is %f\n", y );
}

Output

The floor of 2.8 is 2.000000
The floor of -2.8 is -3.000000
The ceil of 2.8 is 3.000000
The ceil of -2.8 is -2.000000

Floating-Point Support Routines

See Also floor, fmod


_cexit, _c_exit

Perform cleanup operations and return without terminating the process.

void _cexit( void );

void _c_exit( void );

Routine | Required Header | Compatibility
_cexit | <process.h> | Win 95, Win NT
_c_exit | <process.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Remarks

The _cexit function calls, in last-in-first-out (LIFO) order, the functions registered by atexit and _onexit. Then _cexit flushes all I/O buffers and closes all open streams before returning. _c_exit is the same as _exit but returns to the calling process without processing atexit or _onexit or flushing stream buffers. The behavior of exit, _exit, _cexit, and _c_exit is as follows:

Function | Behavior
exit | Performs complete C library termination procedures, terminates process, and exits with supplied status code
_exit | Performs “quick” C library termination procedures, terminates process, and exits with supplied status code
_cexit | Performs complete C library termination procedures and returns to caller, but does not terminate process
_c_exit | Performs “quick” C library termination procedures and returns to caller, but does not terminate process

Process and Environment Control Routines

See Also abort, atexit, _exec Functions, exit, _onexit, _spawn Functions, system


_cgets

Gets a character string from the console.

char *_cgets( char *buffer );

Routine | Required Header | Compatibility
_cgets | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_cgets returns a pointer to the start of the string, at buffer[2]. There is no error return.

Parameter

buffer

Storage location for data

Remarks

The _cgets function reads a string of characters from the console and stores the string and its length in the location pointed to by buffer. The buffer parameter must be a pointer to a character array. The first element of the array, buffer[0], must contain the maximum length (in characters) of the string to be read. The array must contain enough elements to hold the string, a terminating null character ('\0'), and two additional bytes. The function reads characters until a carriage-return – linefeed (CR-LF) combination or the specified number of characters is read. The string is stored starting at buffer[2]. If the function reads a CR-LF, it stores the null character ('\0'). _cgets then stores the actual length of the string in the second array element, buffer [1]. Because all editing keys are active when _cgets is called, pressing F3 repeats the last entry.

Example

/* CGETS.C: This program creates a buffer and initializes
 * the first byte to the size of the buffer: 2. Next, the
 * program accepts an input string using _cgets and displays
 * the size and text of that string.
 */

#include <conio.h>
#include <stdio.h>

void main( void )
{
   char buffer[82] = { 80 };  /* Maximum characters in 1st byte */
   char *result;

   printf( "Input line of text, followed by carriage return:\n");
   result = _cgets( buffer );  /* Input a line of text */
   printf( "\nLine length = %d\nText = %s\n", buffer[1], result );
}

Output

Input line of text, followed by carriage return:
This is a line of text

Line length = 22
Text = This is a line of text.

Console and Port I/O Routines

See Also _getch


_chdir, _wchdir

Change the current working directory.

int _chdir( const char *dirname );

int _wchdir( const wchar_t *dirname );

Routine | Required Header | Optional Headers | Compatibility
_chdir | <direct.h> | <errno.h> | Win 95, Win NT
_wchdir | <direct.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a value of 0 if successful. A return value of –1 indicates that the specified path could not be found, in which case errno is set to ENOENT.

Parameter

dirname

Path of new working directory

Remarks

The _chdir function changes the current working directory to the directory specified by dirname. The dirname parameter must refer to an existing directory. This function can change the current working directory on any drive and if a new drive letter is specified in dirname, the default drive letter will be changed as well. For example, if A is the default drive letter and \BIN is the current working directory, the following call changes the current working directory for drive C and establishes C as the new default drive:

_chdir("c:\\temp");

When you use the optional backslash character (\) in paths, you must place two backslashes (\\) in a C string literal to represent a single backslash (\).

_wchdir is a wide-character version of _chdir; the dirname argument to _wchdir is a wide-character string. _wchdir and _chdir behave identically otherwise.

Generic-Text Routine Mapping:

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tchdir | _chdir | _chdir | _wchdir

Example

/* CHGDIR.C: This program uses the _chdir function to verify
 * that a given directory exists.
 */

#include <direct.h>
#include <stdio.h>
#include <stdlib.h>

void main( int argc, char *argv[] )
{
   if( _chdir( argv[1] )   )
      printf( "Unable to locate the directory: %s\n", argv[1] );
   else
      system( "dir *.wri");
}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 0E17-1702

 Directory of C:\write

04/21/95  01:06p                 3,200 ERRATA.WRI
04/21/95  01:06p                 2,816 README.WRI
               2 File(s)          6,016 bytes
                             71,432,116 bytes free

Directory Control Routines

See Also _mkdir, _rmdir, system


_chdrive

Changes the current working drive.

int _chdrive( int drive );

Routine | Required Header | Compatibility
_chdrive | <direct.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_chdrive returns a value of 0 if the working drive is successfully changed. A return value of –1 indicates an error.

Parameter

drive

Number of new working drive

Remarks

The _chdrive function changes the current working drive to the drive specified by drive. The drive parameter uses an integer to specify the new working drive (1=A, 2=B, and so forth). This function changes only the working drive; _chdir changes the working directory.

Example

/* GETDRIVE.C illustrates drive functions including:
 *      _getdrive       _chdrive        _getdcwd
 */

#include <stdio.h>
#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>

void main( void )
{
   int ch, drive, curdrive;
   static char path[_MAX_PATH];

   /* Save current drive. */
   curdrive = _getdrive();

   printf( "Available drives are: \n" );

   /* If we can switch to the drive, it exists. */
   for( drive = 1; drive <= 26; drive++ )
      if( !_chdrive( drive ) )
         printf( "%c: ", drive + 'A' - 1 );

   while( 1 )
   {
      printf( "\nType drive letter to check or ESC to quit: " );
      ch = _getch();
      if( ch == 27 )
         break;
      if( isalpha( ch ) )
         _putch( ch );
      if( _getdcwd( toupper( ch ) - 'A' + 1, path, _MAX_PATH ) != NULL )
         printf( "\nCurrent directory on that drive is %s\n", path );
   }

   /* Restore original drive.*/
   _chdrive( curdrive );
   printf( "\n" );
}

Output

Available drives are:
A: B: C: L: M: O: U: V:
Type drive letter to check or ESC to quit: c
Current directory on that drive is C:\CODE

Type drive letter to check or ESC to quit: m
Current directory on that drive is M:\

Type drive letter to check or ESC to quit:

Directory Control Routines

See Also _chdir, _fullpath, _getcwd, _getdrive, _mkdir, _rmdir, system


_chgsign

Reverses the sign of a double-precision floating-point argument.

double _chgsign( double x );

Routine | Required Header | Compatibility
_chgsign | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_chgsign returns a value equal to its double-precision floating-point argument x, but with its sign reversed. There is no error return.

Parameter

x

Double-precision floating-point value to be changed

Floating-Point Support Routines

See Also fabs, _copysign


_chmod, _wchmod

Change the file-permission settings.

int _chmod( const char *filename, int pmode );

int _wchmod( const wchar_t *filename, int pmode );

Routine | Required Header | Optional Headers | Compatibility
_chmod | <io.h> | <sys/types.h>, <sys/stat.h>, <errno.h> | Win 95, Win NT
_wchmod | <io.h> or <wchar.h> | <sys/types.h>, <sys/stat.h>, <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if the permission setting is successfully changed. A return value of –1 indicates that the specified file could not be found, in which case errno is set to ENOENT.

Parameters

filename

Name of existing file

pmode

Permission setting for file

Remarks

The _chmod function changes the permission setting of the file specified by filename. The permission setting controls read and write access to the file. The integer expression pmode contains one or both of the following manifest constants, defined in SYS\STAT.H:

_S_IWRITE

Writing permitted

_S_IREAD

Reading permitted

_S_IREAD | _S_IWRITE

Reading and writing permitted

Any other values for pmode are ignored. When both constants are given, they are joined with the bitwise-OR operator ( | ). If write permission is not given, the file is read-only. Note that all files are always readable; it is not possible to give write-only permission. Thus the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent.

_wchmod is a wide-character version of _chmod; the filename argument to _wchmod is a wide-character string. _wchmod and _chmod behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tchmod | _chmod | _chmod | _wchmod

Example

/* CHMOD.C: This program uses _chmod to
 * change the mode of a file to read-only.
 * It then attempts to modify the file.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   /* Make file read-only: */
   if( _chmod( "CHMOD.C", _S_IREAD ) == -1 )
      perror( "File not found\n" );
   else
      printf( "Mode changed to read-only\n" );
   system( "echo /* End of file */ >> CHMOD.C" );

   /* Change back to read/write: */
   if( _chmod( "CHMOD.C", _S_IWRITE ) == -1 )
      perror( "File not found\n" );
   else
      printf( "Mode changed to read/write\n" );
   system( "echo /* End of file */ >> CHMOD.C" );
}

Output

Mode changed to read-only
Access is denied
Mode changed to read/write

File Handling Routines

See Also _access, _creat, _fstat, _open, _stat


_chsize

Changes the file size.

int _chsize( int handle, long size );

Routine | Required Header | Optional Headers | Compatibility
_chsize | <io.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_chsize returns the value 0 if the file size is successfully changed. A return value of –1 indicates an error: errno is set to EACCES if the specified file is locked against access, to EBADF if the specified file is read-only or the handle is invalid, or to ENOSPC if no space is left on the device.

Parameters

handle

Handle referring to open file

size

New length of file in bytes

Remarks

The _chsize function extends or truncates the file associated with handle to the length specified by size. The file must be open in a mode that permits writing. Null characters ('\0') are appended if the file is extended. If the file is truncated, all data from the end of the shortened file to the original length of the file is lost.

Example

/* CHSIZE.C: This program uses _filelength to report the size
 * of a file before and after modifying it with _chsize.
 */

#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

void main( void )
{
   int fh, result;
   unsigned int nbytes = BUFSIZ;

   /* Open a file */
   if( (fh = _open( "data", _O_RDWR | _O_CREAT, _S_IREAD
                   | _S_IWRITE ))  != -1 )
   {
      printf( "File length before: %ld\n", _filelength( fh ) );
      if( ( result = _chsize( fh, 329678 ) ) == 0 )
         printf( "Size successfully changed\n" );
      else
         printf( "Problem in changing the size\n" );
      printf( "File length after:  %ld\n", _filelength( fh ) );
      _close( fh );
   }
}

Output

File length before: 0
Size successfully changed
File length after:  329678

File Handling Routines

See Also _close, _creat, _open


_clear87, _clearfp

Get and clear the floating-point status word.

unsigned int _clear87( void );

unsigned int _clearfp( void );

Routine | Required Header | Compatibility
_clear87 | <float.h> | Win 95, Win NT
_clearfp | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The bits in the value returned indicate the floating-point status before the call to _clear87 or _clearfp. See FLOAT.H for a complete definition of the bits returned by _clear87. Many of the math library functions modify the 8087/80287 status word, with unpredictable results. Return values from _clear87 and _status87 become more reliable as fewer floating-point operations are performed between known states of the floating-point status word.

Remarks

The _clear87 function clears the exception flags in the floating-point status word, sets the busy bit to 0, and returns the status word. The floating-point status word is a combination of the 8087/80287 status word and other conditions detected by the 8087/80287 exception handler, such as floating-point stack overflow and underflow.

_clearfp is a platform-independent, portable version of the _clear87 routine. It is identical to _clear87 on Intel® (x86) platforms and is also supported by the MIPS® and ALPHA platforms. To ensure that your floating-point code is portable to MIPS or ALPHA, use _clearfp. If you are only targeting x86 platforms, you can use either _clear87 or _clearfp.

Example

/* CLEAR87.C: This program creates various floating-point
 * problems, then uses _clear87 to report on these problems.
 * Compile this program with Optimizations disabled (/Od).
 * Otherwise the optimizer will remove the code associated with
 * the unused floating-point values.
 */

#include <stdio.h>
#include <float.h>

void main( void )
{
   double a = 1e-40, b;
   float x, y;

   printf( "Status: %.4x - clear\n", _clear87()  );

   /* Store into y is inexact and underflows: */
   y = a;
   printf( "Status: %.4x - inexact, underflow\n", _clear87() );

   /* y is denormal: */
   b = y;
   printf( "Status: %.4x - denormal\n", _clear87() );
}

Output

Status: 0000 - clear
Status: 0003 - inexact, underflow
Status: 80000 - denormal

Floating-Point Support Routines

See Also _control87, _status87


clearerr

Resets the error indicator for a stream

void clearerr( FILE *stream );

Routine | Required Header | Compatibility
clearerr | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

stream

Pointer to FILE structure

Remarks

The clearerr function resets the error indicator and end-of-file indicator for stream. Error indicators are not automatically cleared; once the error indicator for a specified stream is set, operations on that stream continue to return an error value until clearerr, fseek, fsetpos, or rewind is called.

Example

/* CLEARERR.C: This program creates an error
 * on the standard input stream, then clears
 * it so that future reads won't fail.
 */

#include <stdio.h>

void main( void )
{
   int c;
   /* Create an error by writing to standard input. */
   putc( 'c', stdin );
   if( ferror( stdin ) )
   {
      perror( "Write error" );
      clearerr( stdin );
   }

   /* See if read causes an error. */
   printf( "Will input cause an error? " );
   c = getc( stdin );
   if( ferror( stdin ) )
   {
      perror( "Read error" );
      clearerr( stdin );
   }
}

Output

Write error: No error
Will input cause an error? n

Error Handling Routines | Stream I/O Routines

See Also _eof, feof, ferror, perror


clock

Calculates the processor time used by the calling process.

clock_t clock( void );

Routine | Required Header | Compatibility
clock | <time.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

clock returns the number of clock ticks of elapsed processor time. The returned value is the product of the amount of time that has elapsed since the start of a process and the value of the CLOCKS_PER_SEC constant. If the amount of elapsed time is unavailable, the function returns –1, cast as a clock_t.

Remarks

The clock function tells how much processor time the calling process has used. The time in seconds is approximated by dividing the clock return value by the value of the CLOCKS_PER_SEC constant. In other words, clock returns the number of processor timer ticks that have elapsed. A timer tick is approximately equal to 1/CLOCKS_PER_SEC second. In versions of Microsoft C before 6.0, the CLOCKS_PER_SEC constant was called CLK_TCK.

Example

/* CLOCK.C: This example prompts for how long
 * the program is to run and then continuously
 * displays the elapsed time for that period.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void sleep( clock_t wait );

void main( void )
{
   long    i = 600000L;
   clock_t start, finish;
   double  duration;

   /* Delay for a specified time. */
   printf( "Delay for three seconds\n" );
   sleep( (clock_t)3 * CLOCKS_PER_SEC );
   printf( "Done!\n" );

   /* Measure the duration of an event. */
   printf( "Time to do %ld empty loops is ", i );
   start = clock();
   while( i-- )
      ;
   finish = clock();
   duration = (double)(finish - start) / CLOCKS_PER_SEC;
   printf( "%2.1f seconds\n", duration );
}

/* Pauses for a specified number of milliseconds. */
void sleep( clock_t wait )
{
   clock_t goal;
   goal = wait + clock();
   while( goal > clock() )
      ;
}

Output

Delay for three seconds
Done!
Time to do 600000 empty loops is 0.1 seconds

Time Management Routines

See Also difftime, time


_close

Closes a file.

int _close( int handle );

Routine | Required Header | Optional Headers | Compatibility
_close | <io.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_close returns 0 if the file was successfully closed. A return value of –1 indicates an error, in which case errno is set to EBADF, indicating an invalid file-handle parameter.

Parameter

handle

Handle referring to open file

Remarks

The _close function closes the file associated with handle.

Example

/* OPEN.C: This program uses _open to open a file
 * named OPEN.C for input and a file named OPEN.OUT
 * for output. The files are then closed.
 */

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>

void main( void )
{
   int fh1, fh2;

   fh1 = _open( "OPEN.C", _O_RDONLY );
   if( fh1 == -1 )
      perror( "open failed on input file" );
   else
   {
      printf( "open succeeded on input file\n" );
      _close( fh1 );
   }

   fh2 = _open( "OPEN.OUT", _O_WRONLY | _O_CREAT, _S_IREAD |
                            _S_IWRITE );
   if( fh2 == -1 )
      perror( "Open failed on output file" );
   else
   {
      printf( "Open succeeded on output file\n" );
      _close( fh2 );
   }
}

Output

Open succeeded on input file
Open succeeded on output file

Low-Level I/O Routines

See Also _chsize, _creat, _dup, _open, _unlink


_commit

Flushes a file directly to disk.

int _commit( int handle );

Routine | Required Header | Optional Headers | Compatibility
_commit | <io.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_commit returns 0 if the file was successfully flushed to disk. A return value of –1 indicates an error, and errno is set to EBADF, indicating an invalid file-handle parameter.

Parameter

handle

Handle referring to open file

Remarks

The _commit function forces the operating system to write the file associated with handle to disk. This call ensures that the specified file is flushed immediately, not at the operating system’s discretion.

Example

/* COMMIT.C illustrates low-level file I/O functions including:
 *
 *     _close    _commit    memset    _open    _write
 *
 * This is example code; to keep the code simple and readable
 * return values are not checked.
 */

#include <io.h>
#include <stdio.h>
#include <fcntl.h>
#include <memory.h>
#include <errno.h>

#define MAXBUF 32

int log_receivable( int );

void main( void )
{
    int fhandle;
    fhandle = _open( "TRANSACT.LOG", _O_APPEND | _O_CREAT |
                                     _O_BINARY | _O_RDWR );
    log_receivable( fhandle );
    _close( fhandle );
}

int log_receivable( int fhandle )
{
/* The log_receivable function prompts for a name and a monetary
 * amount and places both values into a buffer (buf). The _write
 * function writes the values to the operating system and the
 * _commit function ensures that they are written to a disk file.
 */

    int i;
    char  buf[MAXBUF];

    memset( buf, '\0', MAXBUF );
    /* Begin Transaction. */
    printf( "Enter name: " );
    gets( buf );
    for( i = 1; buf[i] != '\0'; i++ );
    /* Write the value as a '\0' terminated string. */
    _write( fhandle, buf, i+1 );
    printf( "\n" );

    memset( buf, '\0', MAXBUF );
    printf( "Enter amount: $" );
    gets( buf );
    for( i = 1; buf[i] != '\0'; i++ );
    /* Write the value as a '\0' terminated string. */
    _write( fhandle, buf, i+1 );
    printf( "\n" );

    /* The _commit function ensures that two important pieces of
     * data are safely written to disk. The return value of the
     * _commit function is returned to the calling function.
     */
    return _commit( fhandle );
}

Low-Level I/O Routines

See Also _creat, _open, _read, _write


_control87, _controlfp

Get and set the floating-point control word.

unsigned int _control87( unsigned int new, unsigned int mask );

unsigned int _controlfp( unsigned int new, unsigned int mask );

Routine | Required Header | Compatibility
_control87 | <float.h> | Win 95, Win NT
_controlfp | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The bits in the value returned indicate the floating-point control state. See FLOAT.H for a complete definition of the bits returned by _control87.

Parameters

new

New control-word bit values

mask

Mask for new control-word bits to set

Remarks

The _control87 function gets and sets the floating-point control word. The floating-point control word allows the program to change the precision, rounding, and infinity modes in the floating-point math package. You can also mask or unmask floating-point exceptions using _control87. If the value for mask is equal to 0, _control87 gets the floating-point control word. If mask is nonzero, a new value for the control word is set: For any bit that is on (equal to 1) in mask, the corresponding bit in new is used to update the control word. In other words, fpcntrl = ((fpcntrl & ~mask) | (new & mask)) where fpcntrl is the floating-point control word.

Note The run-time libraries mask all floating-point exceptions by default.

_controlfp is a platform-independent, portable version of _control87. It is nearly identical to the _control87 function on Intel (x86) platforms and is also supported by the MIPS and ALPHA platforms. To ensure that your floating-point code is portable to MIPS or ALPHA, use _controlfp. If you are targeting x86 platforms, use either _control87 or _controlfp.

The difference between _control87 and _controlfp is the way these two functions treat DENORMAL values. For Intel (x86) platforms, _control87 can set and clear the DENORMAL OPERAND exception mask. ALPHA platforms do not support this exception, and _controlfp does not modify the DENORMAL OPERAND exception mask. The following example demonstrates the difference:

_control87( _EM_INVALID, _MCW_EM ); // DENORMAL is unmasked by this call
_controlfp( _EM_INVALID, _MCW_EM ); // DENORMAL exception mask remains unchanged

The possible values for the mask constant (mask) and new control values (new) are shown in Table R.1. Use the portable constants listed below (_MCW_EM, _EM_INVALID, and so forth) as arguments to these functions, rather than supplying the hexadecimal values explicitly.

ALPHA platforms support the DENORMAL input and output values in software. The default behavior of Windows NT on these platforms is to flush the DENORMAL input and output values to zero. _controlfp provides a new mask to preserve and flush the input and output DENORMAL values.

Intel (x86) platforms support the DENORMAL input and output values in hardware. The behavior is to preserve DENORMAL values. _control87 does not provide a mask to change this behavior. The following example demonstrates this difference:

controlfp( _DN_SAVE, _MCW_DN);   // Denormal values preserved by software on ALPHA. NOP on x86
controlfp( _DN_FLUSH, _MCW_DN);   // Denormal values flushed to zero by hardware on Alpha. Ignored on x86

Table R.1 Hexadecimal Values

Mask | Hex Value | Constant | Hex Value
_MCW_DN (Denormal control) | 0x03000000 | _DN_SAVE _DN_FLUSH | 0x00000000 0x01000000
_MCW_EM (Interrupt exception) | 0x0008001F | _EM_INVALID _EM_DENORMAL _EM_ZERODIVIDE _EM_OVERFLOW _EM_UNDERFLOW _EM_INEXACT | 0x00000010 0x00080000 0x00000008 0x00000004 0x00000002 0x00000001
_MCW_IC (Infinity control) | 0x00040000 | _IC_AFFINE _IC_PROJECTIVE | 0x00040000 0x00000000
_MCW_RC (Rounding control) | 0x00000300 | _RC_CHOP _RC_UP _RC_DOWN _RC_NEAR | 0x00000300 0x00000200 0x00000100 0x00000000
_MCW_PC (Precision control) | 0x00030000 | _PC_24 (24 bits) _PC_53 (53 bits) _PC_64 (64 bits) | 0x00020000 0x00010000 0x00000000

Example

/* CNTRL87.C: This program uses _control87 to output the control
 * word, set the precision to 24 bits, and reset the status to
 * the default.
 */

#include <stdio.h>
#include <float.h>

void main( void )
{
   double a = 0.1;

   /* Show original control word and do calculation. */
   printf( "Original: 0x%.4x\n", _control87( 0, 0 ) );
   printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );

   /* Set precision to 24 bits and recalculate. */
   printf( "24-bit:   0x%.4x\n", _control87( _PC_24, MCW_PC ) );
   printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );

   /* Restore to default and recalculate. */
   printf( "Default:  0x%.4x\n",
          _control87( _CW_DEFAULT, 0xfffff ) );
   printf( "%1.1f * %1.1f = %.15e\n", a, a, a * a );
}

Output

Original: 0x9001f
0.1 * 0.1 = 1.000000000000000e-002
24-bit:   0xa001f
0.1 * 0.1 = 9.999999776482582e-003
Default:  0x001f
0.1 * 0.1 = 1.000000000000000e-002

Floating-Point Support Routines

See Also _clear87, _status87


_copysign

Return one value with the sign of another.

double _copysign( double x, double y );

Routine | Required Header | Compatibility
_copysign | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_copysign returns its double-precision floating point argument x with the same sign as its double-precision floating-point argument y. There is no error return.

Parameters

x

Double-precision floating-point value to be changed

y

Double-precision floating-point value

Floating-Point Support Routines

See Also fabs, _chgsign


cos, cosh

Calculate the cosine (cos) or hyperbolic cosine (cosh).

double cos( double x );

double cosh( double x );

Routine | Required Header | Compatibility
cos | <math.h> | ANSI, Win 95, Win NT
cosh | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The cos and cosh functions return the cosine and hyperbolic cosine, respectively, of x. If x is greater than or equal to 263, or less than or equal to –263, a loss of significance in the result of a call to cos occurs, in which case the function generates a _TLOSS error and returns an indefinite (same as a quiet NaN).

If the result is too large in a cosh call, the function returns HUGE_VAL and sets errno to ERANGE. You can modify error handling with _matherr.

Parameter

x

Angle in radians

Example

/* SINCOS.C: This program displays the sine, hyperbolic
 * sine, cosine, and hyperbolic cosine of pi / 2.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double pi = 3.1415926535;
   double x, y;

   x = pi / 2;
   y = sin( x );
   printf( "sin( %f ) = %f\n", x, y );
   y = sinh( x );
   printf( "sinh( %f ) = %f\n",x, y );
   y = cos( x );
   printf( "cos( %f ) = %f\n", x, y );
   y = cosh( x );
   printf( "cosh( %f ) = %f\n",x, y );
}

Output

sin( 1.570796 ) = 1.000000
sinh( 1.570796 ) = 2.301299
cos( 1.570796 ) = 0.000000
cosh( 1.570796 ) = 2.509178

Floating-Point Support Routines

See Also acos, asin, atan, _matherr, sin, tan


_cprintf

Formats and prints to the console.

int _cprintf( const char *format [, argument] ... );

Routine | Required Header | Compatibility
_cprintf | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_cprintf returns the number of characters printed.

Parameters

format

Format-control string

argument

Optional parameters

Remarks

The _cprintf function formats and prints a series of characters and values directly to the console, using the _putch function to output characters. Each argument (if any) is converted and output according to the corresponding format specification in format. The format has the same form and function as the format parameter for the printf function. Unlike the fprintf, printf, and sprintf functions, _cprintf does not translate linefeed characters into carriage return–linefeed (CR-LF) combinations on output.

Example

/* CPRINTF.C: This program displays
 * some variables to the console.
 */

#include <conio.h>

void main( void )
{
   int      i = -16, h = 29;
   unsigned u = 62511;
   char     c = 'A';
   char     s[] = "Test";

   /* Note that console output does not translate \n as
    * standard output does. Use \r\n instead.
    */
   _cprintf( "%d  %.4x  %u  %c %s\r\n", i, h, u, c, s );
}

Output

-16  001d  62511  A Test

Console and Port I/O Routines

See Also _cscanf, fprintf, printf, sprintf, vfprintf


_cputs

Puts a string to the console.

int _cputs( const char *string );

Routine | Required Header | Compatibility
_cputs | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _cputs returns a 0. If the function fails, it returns a nonzero value.

Parameter

string

Output string

Remarks

The _cputs function writes the null-terminated string pointed to by string directly to the console. A carriage return–linefeed (CR-LF) combination is not automatically appended to the string.

Example

/* CPUTS.C: This program first displays
 * a string to the console.
 */

#include <conio.h>

void main( void )
{
   /* String to print at console.
    * Note the \r (return) character.
    */
   char *buffer = "Hello world (courtesy of _cputs)!\r\n";

   _cputs( buffer );
}

Output

Hello world (courtesy of _cputs)!

Console and Port I/O Routines

See Also _putch


_creat, _wcreat

Creates a new file.

int _creat( const char *filename, int pmode );

int _wcreat( const wchar_t *filename, int pmode );

Routine | Required Header | Optional Headers | Compatibility
_creat | <io.h> | <sys/types.h>, <sys/stat.h>, <errno.h> | Win 95, Win NT
_wcreat | <io.h> or <wchar.h> | <sys/types.h>, <sys/stat.h>, <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions, if successful, returns a handle to the created file. Otherwise the function returns –1 and sets errno as follows.

errno Setting | Description
EACCES | Filename specifies an existing read-only file or specifies a directory instead of a file
EMFILE | No more file handles are available
ENOENT | The specified file could not be found

Parameters

filename

Name of new file

pmode

Permission setting

Remarks

The _creat function creates a new file or opens and truncates an existing one. _wcreat is a wide-character version of _creat; the filename argument to _wcreat is a wide-character string. _wcreat and _creat behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcreat | _creat | _creat | _wcreat

If the file specified by filename does not exist, a new file is created with the given permission setting and is opened for writing. If the file already exists and its permission setting allows writing, _creat truncates the file to length 0, destroying the previous contents, and opens it for writing. The permission setting, pmode, applies to newly created files only. The new file receives the specified permission setting after it is closed for the first time. The integer expression pmode contains one or both of the manifest constants _S_IWRITE and _S_IREAD, defined in SYS\STAT.H. When both constants are given, they are joined with the bitwise-OR operator ( | ). The pmode parameter is set to one of the following values:

_S_IWRITE

Writing permitted

_S_IREAD

Reading permitted

_S_IREAD | _S_IWRITE

Reading and writing permitted

If write permission is not given, the file is read-only. All files are always readable; it is impossible to give write-only permission. Thus the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent. Files opened using _creat are always opened in compatibility mode (see _sopen) with _SH_DENYNO.

_creat applies the current file-permission mask to pmode before setting the permissions (see _umask). _creat is provided primarily for compatibility with previous libraries. A call to _open with _O_CREAT and _O_TRUNC in the oflag parameter is equivalent to _creat and is preferable for new code.

Example

/* CREAT.C: This program uses _creat to create
 * the file (or truncate the existing file)
 * named data and open it for writing.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int fh;

   fh = _creat( "data", _S_IREAD | _S_IWRITE );
   if( fh == -1 )
      perror( "Couldn't create data file" );
   else
   {
      printf( "Created data file.\n" );
      _close( fh );
   }
}

Output

Created data file.

Low-Level I/O Routines

See Also _chmod, _chsize, _close, _dup, _open, _sopen, _umask


_cscanf

Reads formatted data from the console.

int _cscanf( const char *format [, argument] ... );

Routine | Required Header | Compatibility
_cscanf | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_cscanf returns the number of fields that were successfully converted and assigned. The return value does not include fields that were read but not assigned. The return value is EOF for an attempt to read at end of file. This can occur when keyboard input is redirected at the operating-system command-line level. A return value of 0 means that no fields were assigned.

Parameters

format

Format-control string

argument

Optional parameters

Remarks

The _cscanf function reads data directly from the console into the locations given by argument. The _getche function is used to read characters. Each optional parameter must be a pointer to a variable with a type that corresponds to a type specifier in format. The format controls the interpretation of the input fields and has the same form and function as the format parameter for the scanf function. While _cscanf normally echoes the input character, it does not do so if the last call was to _ungetch.

Example

/* CSCANF.C: This program prompts for a string
 * and uses _cscanf to read in the response.
 * Then _cscanf returns the number of items
 * matched, and the program displays that number.
 */

#include <stdio.h>
#include <conio.h>

void main( void )
{
   int   result, i[3];

   _cprintf( "Enter three integers: ");
   result = _cscanf( "%i %i %i", &i[0], &i[1], &i[2] );
   _cprintf( "\r\nYou entered " );
   while( result-- )
      _cprintf( "%i ", i[result] );
   _cprintf( "\r\n" );
}

Output

Enter three integers: 1  2  3
You entered 3 2 1

Console and Port I/O Routines

See Also _cprintf, fscanf, scanf, sscanf


ctime, _wctime

Convert a time value to a string and adjust for local time zone settings.

char *ctime( const time_t *timer );

wchar_t *_wctime( const time_t *timer );

Routine | Required Header | Compatibility
ctime | <time.h> | ANSI, Win 95, Win NT
_wctime | <time.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the character string result. If time represents a date before midnight, January 1, 1970, UTC, the function returns NULL.

Parameter

timer

Pointer to stored time

Remarks

The ctime function converts a time value stored as a time_t structure into a character string. The timer value is usually obtained from a call to time, which returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC). The string result produced by ctime contains exactly 26 characters and has the form:

Wed Jan 02 02:03:55 1980\n\0

A 24-hour clock is used. All fields have a constant width. The newline character ('\n') and the null character ('\0') occupy the last two positions of the string.

The converted character string is also adjusted according to the local time zone settings. See the time, _ftime, and localtime functions for information on configuring the local time and the _tzset function for details about defining the time zone environment and global variables.

A call to ctime modifies the single statically allocated buffer used by the gmtime and localtime functions. Each call to one of these routines destroys the result of the previous call. ctime shares a static buffer with the asctime function. Thus, a call to ctime destroys the results of any previous call to asctime, localtime, or gmtime.

_wctime is a wide-character version of ctime; _wctime returns a pointer to a wide-character string. _wctime and ctime behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tctime | ctime | ctime | _wctime

Example

/* CTIME.C: This program gets the current
 * time in time_t form, then uses ctime to
 * display the time in string form.
 */

#include <time.h>
#include <stdio.h>

void main( void )
{
   time_t ltime;

   time( &ltime );
   printf( "The time is %s\n", ctime( &ltime ) );
}

Output

The time is Fri Apr 29 12:25:12 1994

Time Management Routines

See Also asctime, _ftime, gmtime, localtime, time


_cwait

Waits until another process terminates.

int _cwait( int *termstat, int procHandle, int action );

Routine | Required Header | Optional Headers | Compatibility
_cwait | <process.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

When the specified process has “successfully” completed, _cwait returns the handle of the specified process and sets termstat to the result code returned by the specified process. Otherwise, _cwait returns –1 and sets errno as follows.

Value | Description
ECHILD | No specified process exists, procHandle is invalid, or the call to the GetExitCodeProcess or WaitForSingleObject API failed
EINVAL | action is invalid

Parameters

termstat

Pointer to a buffer where the result code of the specified process will be stored, or NULL

procHandle

Handle to the current process or thread

action

NULL: Ignored by Windows NT and Windows 95 applications; for other applications: action code to perform on procHandle

Remarks

The _cwait function waits for the termination of the process ID of the specified process that is provided by procHandle. The value of procHandle passed to _cwait should be the value returned by the call to the _spawn function that created the specified process. If the process ID terminates before _cwait is called, _cwait returns immediately. _cwait can be used by any process to wait for any other known process for which a valid handle (procHandle) exists.

termstat points to a buffer where the return code of the specified process will be stored. The value of termstat indicates whether the specified process terminated “normally” by calling the Windows NT ExitProcess API. ExitProcess is called internally if the specified process calls exit or _exit, returns from main, or reaches the end of main. See GetExitCodeProcess for more information regarding the value passed back through termstat. If _cwait is called with a NULL value for termstat, the return code of the specified process will not be stored.

The action parameter is ignored by Windows NT and Windows 95 because parent-child relationships are not implemented in these environments. Therefore, the OS/2 wait function, which allows a parent process to wait for any of its immediate children to terminate, is not available.

Example

/* CWAIT.C: This program launches several processes and waits
 * for a specified process to finish.
 */

#include <windows.h>
#include <process.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>

/* Macro to get a random integer within a specified range */
#define getrandom( min, max ) (( rand() % (int)((( max ) + 1 ) - ( min ))) + ( min ))

struct PROCESS
{

   int     nPid;
   char    name[40];

} process[4] = { { 0, "Ann" }, { 0, "Beth" }, { 0, "Carl" }, { 0, "Dave" } };

void main( int argc, char *argv[] )
{

   int termstat, c;

   srand( (unsigned)time( NULL ) );    /* Seed randomizer */
   /* If no arguments, this is the calling process */
   if( argc == 1 )
   {

      /* Spawn processes in numeric order */
      for( c = 0; c < 4; c++ ){
         _flushall();
         process[c].nPid = spawnl( _P_NOWAIT, argv[0], argv[0],
                             process[c].name, NULL );
      }

      /* Wait for randomly specified process, and respond when done */
      c = getrandom( 0, 3 );
      printf( "Come here, %s.\n", process[c].name );
      _cwait( &termstat, process[c].nPid, _WAIT_CHILD );
      printf( "Thank you, %s.\n", process[c].name );

   }

   /* If there are arguments, this must be a spawned process */
   else
   {

      /* Delay for a period determined by process number */
      Sleep( (argv[1][0] - 'A' + 1) * 1000L );
      printf( "Hi, Dad. It's %s.\n", argv[1] );

   }

}

Output

Hi, Dad. It's Ann.
Come here, Ann.
Thank you, Ann.
Hi, Dad. It's Beth.
Hi, Dad. It's Carl.
Hi, Dad. It's Dave.

Process and Environment Control Routines

See Also _spawn Functions


difftime

Finds the difference between two times.

double difftime( time_t timer1, time_t timer0 );

Routine | Required Header | Compatibility
difftime | <time.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

difftime returns the elapsed time in seconds, from timer0 to timer1. The value returned is a double-precision floating-point number.

Parameters

timer1

Ending time

timer0

Beginning time

Remarks

The difftime function computes the difference between the two supplied time values timer0 and timer1.

Example

/* DIFFTIME.C: This program calculates the amount of time
 * needed to do a floating-point multiply 10 million times.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void main( void )
{
   time_t   start, finish;
   long loop;
   double   result, elapsed_time;

   printf( "Multiplying 2 floating point numbers 10 million times...\n" );

   time( &start );
   for( loop = 0; loop < 10000000; loop++ )
      result = 3.63 * 5.27;
   time( &finish );

   elapsed_time = difftime( finish, start );
   printf( "\nProgram takes %6.0f seconds.\n", elapsed_time );
}

Output

Multiplying 2 floats 10 million times...

Program takes      2 seconds.

Floating-Point Support Routines | Time Management Routines

See Also time


div

Computes the quotient and the remainder of two integer values.

div_t div( int numer, int denom );

Routine | Required Header | Compatibility
div | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

div returns a structure of type div_t, comprising the quotient and the remainder. The structure is defined in STDLIB.H.

Parameters

numer

Numerator

denom

Denominator

Remarks

The div function divides numer by denom, computing the quotient and the remainder. The div_t structure contains int quot, the quotient, and int rem, the remainder. The sign of the quotient is the same as that of the mathematical quotient. Its absolute value is the largest integer that is less than the absolute value of the mathematical quotient. If the denominator is 0, the program terminates with an error message.

Example

/* DIV.C: This example takes two integers as command-line
 * arguments and displays the results of the integer
 * division. This program accepts two arguments on the
 * command line following the program name, then calls
 * div to divide the first argument by the second.
 * Finally, it prints the structure members quot and rem.
 */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

void main( int argc, char *argv[] )
{
   int x,y;
   div_t div_result;

   x = atoi( argv[1] );
   y = atoi( argv[2] );

   printf( "x is %d, y is %d\n", x, y );
   div_result = div( x, y );
   printf( "The quotient is %d, and the remainder is %d\n",
           div_result.quot, div_result.rem );
}

Output

x is 876, y is 13
The quotient is 67, and the remainder is 5

Floating-Point Support Routines

See Also ldiv


_dup, _dup2

Create a second handle for an open file (_dup), or reassign a file handle (_dup2).

int_dup( int handle );

int _dup2( int handle1, int handle2 );

Routine | Required Header | Compatibility
_dup | <io.h> | Win 95, Win NT
_dup2 | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_dup returns a new file handle. _dup2 returns 0 to indicate success. If an error occurs, each function returns –1 and sets errno to EBADF if the file handle is invalid, or to EMFILE if no more file handles are available.

Parameters

handle, handle1

Handles referring to open file

handle2

Any handle value

Remarks

The _dup and _dup2 functions associate a second file handle with a currently open file. These functions can be used to associate a predefined file handle, such as that for stdout, with a different file. Operations on the file can be carried out using either file handle. The type of access allowed for the file is unaffected by the creation of a new handle. _dup returns the next available file handle for the given file._dup2 forces handle2 to refer to the same file as handle1. If handle2 is associated with an open file at the time of the call, that file is closed.

Both _dup and _dup2 accept file handles as parameters. To pass a stream (FILE *) to either of these functions, use _fileno. The fileno routine returns the file handle currently associated with the given stream. The following example shows how to associate stderr (defined as FILE * in STDIO.H) with a handle:

cstderr = _dup( _fileno( stderr ));

Example

/* DUP.C: This program uses the variable old to save
 * the original stdout. It then opens a new file named
 * new and forces stdout to refer to it. Finally, it
 * restores stdout to its original state.
 */

#include <io.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int old;
   FILE *new;

   old = _dup( 1 );   /* "old" now refers to "stdout" */
                      /* Note:  file handle 1 == "stdout" */
   if( old == -1 )
   {
      perror( "_dup( 1 ) failure" );
      exit( 1 );
   }
   write( old, "This goes to stdout first\r\n", 27 );
   if( ( new = fopen( "data", "w" ) ) == NULL )
   {
      puts( "Can't open file 'data'\n" );
      exit( 1 );
   }

   /* stdout now refers to file "data" */
   if( -1 == _dup2( _fileno( new ), 1 ) )
   {
      perror( "Can't _dup2 stdout" );
      exit( 1 );
   }
   puts( "This goes to file 'data'\r\n" );

   /* Flush stdout stream buffer so it goes to correct file */
   fflush( stdout );
   fclose( new );

   /* Restore original stdout */
   _dup2( old, 1 );
   puts( "This goes to stdout\n" );
   puts( "The file 'data' contains:" );
   system( "type data" );
}

Output

This goes to stdout first
This goes to file 'data'

This goes to stdout

The file 'data' contains:

This goes to file 'data'

Low-level I/O Routines

See Also _close, _creat, _open


_ecvt

Converts a double number to a string.

char *_ecvt( double value, int count, int *dec, int *sign );

Function | Required Header | Compatibility
_ecvt | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ecvt returns a pointer to the string of digits. There is no error return.

Parameters

value

Number to be converted

count

Number of digits stored

dec

Stored decimal-point position

sign

Sign of converted number

Remarks

The _ecvt function converts a floating-point number to a character string. The value parameter is the floating-point number to be converted. This function stores up to count digits of value as a string and appends a null character ('\0'). If the number of digits in value exceeds count, the low-order digit is rounded. If there are fewer than count digits, the string is padded with zeros.

Only digits are stored in the string. The position of the decimal point and the sign of value can be obtained from dec and sign after the call. The dec parameter points to an integer value giving the position of the decimal point with respect to the beginning of the string. A 0 or negative integer value indicates that the decimal point lies to the left of the first digit. The sign parameter points to an integer that indicates the sign of the converted number. If the integer value is 0, the number is positive. Otherwise, the number is negative.

_ecvt and _fcvt use a single statically allocated buffer for the conversion. Each call to one of these routines destroys the result of the previous call.

Example

/* ECVT.C: This program uses _ecvt to convert a
 * floating-point number to a character string.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int     decimal,   sign;
   char    *buffer;
   int     precision = 10;
   double  source = 3.1415926535;

   buffer = _ecvt( source, precision, &decimal, &sign );
   printf( "source: %2.10f   buffer: '%s'  decimal: %d  sign: %d\n",
           source, buffer, decimal, sign );
}

Output

source: 3.1415926535   buffer: '3141592654'  decimal: 1   sign: 0

Data Conversion Routines | Floating-Point Support Routines

See Also atof, _fcvt, _gcvt


_endthread, _endthreadex

void _endthread( void );

void _endthreadex( unsigned retval );

Function | Required Header | Compatibility
_endthread | <process.h> | Win 95, Win NT
_endthreadex | <process.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

retval

Thread exit code

Remarks

The _endthread and _endthreadex functions terminate a thread created by _beginthread or _beginthreadex, respectively. You can call _endthread or _endthreadex explicitly to terminate a thread; however, _endthread or _endthreadex is called automatically when the thread returns from the routine passed as a parameter to _beginthread or _beginthreadex. Terminating a thread with a call to endthread or _endthreadex helps to ensure proper recovery of resources allocated for the thread.

Note For an executable file linked with LIBCMT.LIB, do not call the Win32 ExitThread API; this prevents the run-time system from reclaiming allocated resources. _endthread and _endthreadex reclaim allocated thread resources and then call ExitThread.

_endthread automatically closes the thread handle. (This behavior differs from the Win32 ExitThread API.) Therefore, when you use _beginthread and _endthread, do not explicitly close the thread handle by calling the Win32 CloseHandle API.

Like the Win32 ExitThread API, _endthreadex does not close the thread handle. Therefore, when you use _beginthreadex and _endthreadex, you must close the thread handle by calling the Win32 CloseHandle API.

Example

/* BEGTHRD.C illustrates multiple threads using functions:
 *
 *      _beginthread            _endthread
 *
 *
 * This program requires the multithreaded library. For example,
 * compile with the following command line:
 *     CL /MT /D "_X86_" BEGTHRD.C
 *
 * If you are using the Visual C++ development environment, select the
 * Multi-Threaded runtime library in the compiler Project Options dialog
 * box.
 *
 */

#include <windows.h>
#include <process.h>    /* _beginthread, _endthread */
#include <stddef.h>
#include <stdlib.h>
#include <conio.h>

void Bounce( void *ch );
void CheckKey( void *dummy );

/* GetRandom returns a random integer between min and max. */
#define GetRandom( min, max ) ((rand() % (int)(((max) + 1) - (min))) + (min))

BOOL repeat = TRUE;     /* Global repeat flag and video variable */
HANDLE hStdOut;         /* Handle for console window */
CONSOLE_SCREEN_BUFFER_INFO csbi;    /* Console information structure */

void main()
{
    CHAR    ch = 'A';

    hStdOut = GetStdHandle( STD_OUTPUT_HANDLE );

    /* Get display screen's text row and column information. */
   GetConsoleScreenBufferInfo( hStdOut, &csbi );

    /* Launch CheckKey thread to check for terminating keystroke. */
    _beginthread( CheckKey, 0, NULL );

    /* Loop until CheckKey terminates program. */
    while( repeat )
    {
        /* On first loops, launch character threads. */
        _beginthread( Bounce, 0, (void *) (ch++)  );

        /* Wait one second between loops. */
        Sleep( 1000L );
    }
}

/* CheckKey - Thread to wait for a keystroke, then clear repeat flag. */
void CheckKey( void *dummy )
{
    _getch();
    repeat = 0;    /* _endthread implied */

}

/* Bounce - Thread to create and and control a colored letter that moves
 * around on the screen.
 *
 * Params: ch - the letter to be moved
 */
void Bounce( void *ch )
{
    /* Generate letter and color attribute from thread argument. */
    char    blankcell = 0x20;
    char    blockcell = (char) ch;
    BOOL    first = TRUE;
   COORD   oldcoord, newcoord;
   DWORD   result;

    /* Seed random number generator and get initial location. */
    srand( _threadid );
    newcoord.X = GetRandom( 0, csbi.dwSize.X - 1 );
    newcoord.Y = GetRandom( 0, csbi.dwSize.Y - 1 );
    while( repeat )
    {
        /* Pause between loops. */
        Sleep( 100L );

        /* Blank out our old position on the screen, and draw new letter. */
        if( first )
            first = FALSE;
        else
         WriteConsoleOutputCharacter( hStdOut, &blankcell, 1, oldcoord, &result );
         WriteConsoleOutputCharacter( hStdOut, &blockcell, 1, newcoord, &result );

        /* Increment the coordinate for next placement of the block. */
        oldcoord.X = newcoord.X;
        oldcoord.Y = newcoord.Y;
        newcoord.X += GetRandom( -1, 1 );
        newcoord.Y += GetRandom( -1, 1 );

        /* Correct placement (and beep) if about to go off the screen. */
        if( newcoord.X < 0 )
            newcoord.X = 1;
        else if( newcoord.X == csbi.dwSize.X )
            newcoord.X = csbi.dwSize.X - 2;
        else if( newcoord.Y < 0 )
            newcoord.Y = 1;
        else if( newcoord.Y == csbi.dwSize.Y )
            newcoord.Y = csbi.dwSize.Y - 2;

        /* If not at a screen border, continue, otherwise beep. */
        else
            continue;
        Beep( ((char) ch - 'A') * 100, 175 );
    }
    /* _endthread given to terminate */
    _endthread();
}

Process and Environment Control Routines

See Also _beginthread


_eof

Tests for end-of-file.

int _eof( int handle );

Function | Required Header | Optional Headers | Compatibility
_eof | <io.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_eof returns 1 if the current position is end of file, or 0 if it is not. A return value of –1 indicates an error; in this case, errno is set to EBADF, which indicates an invalid file handle.

Parameter

handle

Handle referring to open file

Remarks

The _eof function determines whether the end of the file associated with handle has been reached.

Example

/* EOF.C: This program reads data from a file
 * ten bytes at a time until the end of the
 * file is reached or an error is encountered.
 */
#include <io.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
void main( void )
{
   int  fh, count, total = 0;
   char buf[10];
   if( (fh = _open( "eof.c", _O_RDONLY )) == - 1 )
   {
        perror( "Open failed");
        exit( 1 );
   }
   /* Cycle until end of file reached: */
   while( !_eof( fh ) )
   {
      /* Attempt to read in 10 bytes: */
      if( (count = _read( fh, buf, 10 )) == -1 )
      {
         perror( "Read error" );
         break;
      }
      /* Total actual bytes read */
      total += count;
   }
   printf( "Number of bytes read = %d\n", total );
   _close( fh );
}

Output

Number of bytes read = 754

Error Handling Routines, Low-level I/O Routines

See Also clearerr, feof, ferror, perror


_exec, _wexec Functions

Each of the functions in this family loads and executes a new process.

_execl, _wexecl | _execv, _wexecv
_execle, _wexecle | _execve, _wexecve
_execlp, _wexeclp | _execvp, _wexecvp
_execlpe, _wexeclpe | _execvpe, _wexecvpe

The letter(s) at the end of the function name determine the variation.

_exec Function Suffix | Description
e | envp, array of pointers to environment settings, is passed to new process.
l | Command-line arguments are passed individually to _exec function. Typically used when number of parameters to new process is known in advance.
p | PATH environment variable is used to find file to execute.
v | argv, array of pointers to command-line arguments, is passed to _exec. Typically used when number of parameters to new process is variable.

Remarks

Each of the _exec functions loads and execute a new process. All _exec functions use the same operating-system function. The _exec functions automatically handle multibyte-character string arguments as appropriate, recognizing multibyte-character sequences according to the multibyte code page currently in use. The _wexec functions are wide-character versions of the _exec functions. The _wexec functions behave identically to their _exec family counterparts except that they do not handle multibyte-character strings.

Generic-Text Routine Mappings:

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_texecl | _execl | _execl | _wexecl
_texecle | _execle | _execle | _wexecle
_texeclp | _execlp | _execlp | _wexeclp
_texeclpe | _execlpe | _execlpe | _wexeclpe
_texecv | _execv | _execv | _wexecv
_texecve | _execve | _execve | _wexecve
_texecvp | _execvp | _execvp | _wexecvp
_texecvpe | _execvpe | _execvpe | _wexecvpe

When a call to an _exec function is successful, the new process is placed in the memory previously occupied by the calling process. Sufficient memory must be available for loading and executing the new process.

The cmdname parameter specifies the file to be executed as the new process. It can specify a full path (from the root), a partial path (from the current working directory), or a filename. If cmdname does not have a filename extension or does not end with a period (.), the _exec function searches for the named file. If the search is unsuccessful, it tries the same base name with the .COM extension and then with the .EXE, .BAT, and .CMD extensions. If cmdname has an extension, only that extension is used in the search. If cmdname ends with a period, the _exec function searches for cmdname with no extension. _execlp, _execlpe, _execvp, and _execvpe search for cmdname (using the same procedures) in the directories specified by the PATH environment variable. If cmdname contains a drive specifier or any slashes (that is, if it is a relative path), the _exec call searches only for the specified file; the path is not searched.

Parameters are passed to the new process by giving one or more pointers to character strings as parameters in the _exec call. These character strings form the parameter list for the new process. The combined length of the inherited environment settings and the strings forming the parameter list for the new process must not exceed 32K bytes. The terminating null character ('\0') for each string is not included in the count, but space characters (inserted automatically to separate the parameters) are counted.

The argument pointers can be passed as separate parameters (in _execl, _execle, _execlp, and _execlpe) or as an array of pointers (in _execv, _execve, _execvp, and _execvpe). At least one parameter, arg0, must be passed to the new process; this parameter is argv[0] of the new process. Usually, this parameter is a copy of cmdname. (A different value does not produce an error.)

The _execl, _execle, _execlp, and _execlpe calls are typically used when the number of parameters is known in advance. The parameter arg0 is usually a pointer to cmdname. The parameters arg1 through argn point to the character strings forming the new parameter list. A null pointer must follow argn to mark the end of the parameter list.

The _execv, _execve, _execvp, and _execvpe calls are useful when the number of parameters to the new process is variable. Pointers to the parameters are passed as an array, argv. The parameter argv[0] is usually a pointer to cmdname. The parameters argv[1] through argv[n] point to the character strings forming the new parameter list. The parameter argv[n+1] must be a NULL pointer to mark the end of the parameter list.

Files that are open when an _exec call is made remain open in the new process. In _execl, _execlp, _execv, and _execvp calls, the new process inherits the environment of the calling process. _execle, _execlpe, _execve, and _execvpe calls alter the environment for the new process by passing a list of environment settings through the envp parameter. envp is an array of character pointers, each element of which (except for the final element) points to a null-terminated string defining an environment variable. Such a string usually has the form NAME=value where NAME is the name of an environment variable and value is the string value to which that variable is set. (Note that value is not enclosed in double quotation marks.) The final element of the envp array should be NULL. When envp itself is NULL, the new process inherits the environment settings of the calling process.

A program executed with one of the _exec functions is always loaded into memory as if the “maximum allocation” field in the program’s .EXE file header were set to the default value of 0xFFFFH. You can use the EXEHDR utility to change the maximum allocation field of a program; however, such a program invoked with one of the _exec functions may behave differently from a program invoked directly from the operating-system command line or with one of the _spawn functions.

The _exec calls do not preserve the translation modes of open files. If the new process must use files inherited from the calling process, use the _setmode routine to set the translation mode of these files to the desired mode. You must explicitly flush (using fflush or _flushall) or close any stream before the _exec function call. Signal settings are not preserved in new processes that are created by calls to _exec routines. The signal settings are reset to the default in the new process.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execl, _wexecl

Load and execute new child processes.

int _execl( const char *cmdname, const char *arg0, ... const char *argn, NULL );

int _wexecl( const wchar_t *cmdname, const wchar_t *arg0, ... const wchar_t *argn, NULL );

Function | Required Header | Optional Headers | Compatibility
_execl | <process.h> | <errno.h> | Win 95, Win NT
_wexecl | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to be executed

arg0, ... argn

List of pointers to parameters

Remarks

Each of these functions loads and executes a new process, passing each command-line argument as a separate parameter.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execle, _wexecle

Load and execute new child processes.

int _execle( const char *cmdname, const char *arg0, ... const char *argn, NULL, const char *const *envp );

int _wexecle( const wchar_t *cmdname, const wchar_t *arg0, ... const wchar_t *argn, NULL, const char *const *envp );

Function | Required Header | Optional Headers | Compatibility
_execle | <process.h> | <errno.h> | Win 95, Win NT
_wexecle | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to execute

arg0, ... argn

List of pointers to parameters

envp

Array of pointers to environment settings

Remarks

Each of these functions loads and executes a new process, passing each command-line argument as a separate parameter and also passing an array of pointers to environment settings.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execlp, _wexeclp

Load and execute new child processes.

int _execlp( const char *cmdname, const char *arg0, ... const char *argn, NULL );

int _wexeclp( const wchar_t *cmdname, const wchar_t *arg0, ... const wchar_t *argn, NULL );

Function | Required Header | Optional Headers | Compatibility
_execlp | <process.h> | <errno.h> | Win 95, Win NT
_wexeclp | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to execute

arg0, ... argn

List of pointers to parameters

Remarks

Each of these functions loads and executes a new process, passing each command-line argument as a separate parameter and using the PATH environment variable to find the file to execute.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execlpe, _wexeclpe

Load and execute new child processes.

int _execlpe( const char *cmdname, const char *arg0, ... const char *argn, NULL, const char *const *envp );

int _wexeclpe( const wchar_t *cmdname, const wchar_t *arg0, ... const wchar_t *argn, NULL, const wchar_t *const *envp );

Function | Required Header | Optional Headers | Compatibility
_execlpe | <process.h> | <errno.h> | Win 95, Win NT
_wexeclpe | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to execute

arg0, ... argn

List of pointers to parameters

envp

Array of pointers to environment settings

Remarks

Each of these functions loads and executes a new process, passing each command-line argument as a separate parameter and also passing an array of pointers to environment settings. These functions use the PATH environment variable to find the file to execute.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execv, _wexecv

Load and execute new child processes.

int _execv( const char *cmdname, const char *const *argv );

int _wexecv( const wchar_t *cmdname, const wchar_t *const *argv );

Function | Required Header | Optional Headers | Compatibility
_execv | <process.h> | <errno.h> | Win 95, Win NT
_wexecv | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to execute

argv

Array of pointers to parameters

Remarks

Each of these functions loads and executes a new process, passing an array of pointers to command-line arguments.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execve, _wexecve

Load and execute new child processes.

int _execve( const char *cmdname, const char *const *argv, const char *const *envp );

int _wexecve( const wchar_t *cmdname, const wchar_t *const *argv, const wchar_t *const *envp );

Function | Required Header | Optional Headers | Compatibility
_execve | <process.h> | <errno.h> | Win 95, Win NT
_wexecve | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to execute

argv

Array of pointers to parameters

envp

Array of pointers to environment settings

Remarks

Each of these functions loads and executes a new process, passing an array of pointers to command-line arguments and an array of pointers to environment settings.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execvp, _wexecvp

Load and execute new child processes.

int _execvp( const char *cmdname, const char *const *argv );

int _wexecvp( const wchar_t *cmdname, const wchar_t *const *argv );

Function | Required Header | Optional Headers | Compatibility
_execvp | <process.h> | <errno.h> | Win 95, Win NT
_wexecvp | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to execute

argv

Array of pointers to parameters

Remarks

Each of these functions loads and executes a new process, passing an array of pointers to command-line arguments and using the PATH environment variable to find the file to execute.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


_execvpe, _wexecvpe

Load and execute new child processes.

int _execvpe( const char *cmdname, const char *const *argv, const char *const *envp );

int _wexecvpe( const wchar_t *cmdname, const wchar_t *const *argv, const wchar_t *const *envp );

Function | Required Header | Optional Headers | Compatibility
_execvpe | <process.h> | <errno.h> | Win 95, Win NT
_wexecvpe | <process.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, these functions do not return to the calling process. A return value of –1 indicates an error, in which case the errno global variable is set.

errno Value | Description
E2BIG | The space required for the arguments and environment settings exceeds 32K.
EACCES | The specified file has a locking or sharing violation.
EMFILE | Too many files open (the specified file must be opened to determine whether it is executable).
ENOENT | File or path not found.
ENOEXEC | The specified file is not executable or has an invalid executable-file format.
ENOMEM | Not enough memory is available to execute the new process; or the available memory has been corrupted; or an invalid block exists, indicating that the calling process was not allocated properly.

Parameters

cmdname

Path of file to execute

argv

Array of pointers to parameters

envp

Array of pointers to environment settings

Remarks

Each of these functions loads and executes a new process, passing an array of pointers to command-line arguments and an array of pointers to environment settings. These functions use the PATH environment variable to find the file to execute.

Example

/* EXEC.C illustrates the different versions of exec including:
 *      _execl          _execle          _execlp          _execlpe
 *      _execv          _execve          _execvp          _execvpe
 *
 * Although EXEC.C can exec any program, you can verify how
 * different versions handle arguments and environment by
 * compiling and specifying the sample program ARGS.C. See
 * SPAWN.C for examples of the similar spawn functions.
 */

#include <stdio.h>
#include <conio.h>
#include <process.h>

char *my_env[] =                /* Environment for exec?e */
{
   "THIS=environment will be",
   "PASSED=to new process by",
   "the EXEC=functions",
   NULL
};

void main()
{
   char *args[4], prog[80];
   int ch;

   printf( "Enter name of program to exec: " );
   gets( prog );
   printf( " 1. _execl  2. _execle  3. _execlp  4. _execlpe\n" );
   printf( " 5. _execv  6. _execve  7. _execvp  8. _execvpe\n" );
   printf( "Type a number from 1 to 8 (or 0 to quit): " );
   ch = _getche();
   if( (ch < '1') || (ch > '8') )
       exit( 1 );
   printf( "\n\n" );

   /* Arguments for _execv? */
   args[0] = prog;
   args[1] = "exec??";
   args[2] = "two";
   args[3] = NULL;

   switch( ch )
   {
   case '1':
      _execl( prog, prog, "_execl", "two", NULL );
      break;
   case '2':
      _execle( prog, prog, "_execle", "two", NULL, my_env );
      break;
   case '3':
      _execlp( prog, prog, "_execlp", "two", NULL );
      break;
   case '4':
      _execlpe( prog, prog, "_execlpe", "two", NULL, my_env );
      break;
   case '5':
      _execv( prog, args );
      break;
   case '6':
      _execve( prog, args, my_env );
      break;
   case '7':
      _execvp( prog, args );
      break;
   case '8':
      _execvpe( prog, args, my_env );
      break;
   default:
      break;
   }

   /* This point is reached only if exec fails. */
   printf( "\nProcess was not execed." );
   exit( 0 );
}

Process and Environment Control Routines | _exec, _wexec_Function Overview

See Also abort, atexit, exit, _onexit, _spawn Function Overview, system


exit, _exit

Terminate the calling process after cleanup (exit) or immediately (_exit).

void exit( int status );

void _exit( int status );

Function | Required Header | Compatibility
exit | <process.h> or <stdlib.h> | ANSI, Win 95, Win NT
_exit | <process.h> or <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

status

Exit status

Remarks

The exit and _exit functions terminate the calling process. exit calls, in last-in-first-out (LIFO) order, the functions registered by atexit and _onexit, then flushes all file buffers before terminating the process. _exit terminates the process without processing atexit or _onexit or flushing stream buffers. The status value is typically set to 0 to indicate a normal exit and set to some other value to indicate an error.

Although the exit and _exit calls do not return a value, the low-order byte of status is made available to the waiting calling process, if one exists, after the calling process exits. The status value is available to the operating-system batch command ERRORLEVEL and is represented by one of two constants: EXIT_SUCCESS, which represents a value of 0, or EXIT_FAILURE, which represents a value of 1. The behavior of exit, _exit, _cexit, and _c_exit is as follows.

Function | Description
exit | Performs complete C library termination procedures, terminates the process, and exits with the supplied status code.
_exit | Performs “quick” C library termination procedures, terminates the process, and exits with the supplied status code.
_cexit | Performs complete C library termination procedures and returns to the caller, but does not terminate the process.
_c_exit | Performs “quick” C library termination procedures and returns to the caller, but does not terminate the process.

Example

/* EXITER.C: This program prompts the user for a yes
 * or no and returns an exit code of 1 if the
 * user answers Y or y; otherwise it returns 0. The
 * error code could be tested in a batch file.
 */

#include <conio.h>
#include <stdlib.h>

void main( void )
{
   int ch;

   _cputs( "Yes or no? " );
   ch = _getch();
   _cputs( "\r\n" );
   if( toupper( ch ) == 'Y' )
      exit( 1 );
   else
      exit( 0 );
}

Process and Environment Control Routines

See Also abort, atexit, _cexit, _exec Function Overview, _onexit, _spawn Function Overview, system


exp

Calculates the exponential.

double exp( double x );

Function | Required Header | Compatibility
exp | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The exp function returns the exponential value of the floating-point parameter, x, if successful. On overflow, the function returns INF (infinite) and on underflow, exp returns 0.

Parameter

x

Floating-point value

Example

/* EXP.C */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.302585093, y;

   y = exp( x );
   printf( "exp( %f ) = %f\n", x, y );
}

Output

exp( 2.302585 ) = 10.000000

Floating-Point Support Routines

See Also log


_expand

Changes the size of a memory block.

void *_expand( void *memblock, size_t size );

Function | Required Header | Compatibility
_expand | <malloc.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_expand returns a void pointer to the reallocated memory block. _expand, unlike realloc, cannot move a block to change its size. Thus, if there is sufficient memory available to expand the block without moving it, the memblock parameter to _expand is the same as the return value.

_expand returns NULL when an error is detected during its operation. For example, if _expand is used to shrink a memory block, it might detect a corruption in the small block heap or an invalid block pointer and return NULL.

if there is insufficient memory available to expand the block to the given size without moving it. The item pointed to by memblock is expanded as much as possible in its current location.

The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To check the new size of the item, use _msize. To get a pointer to a type other than void, use a type cast on the return value.

Parameters

memblock

Pointer to previously allocated memory block

size

New size in bytes

Remarks

The _expand function changes the size of a previously allocated memory block by trying to expand or contract the block without moving its location in the heap. The memblock parameter points to the beginning of the block. The size parameter gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes. memblock can also point to a block that has been freed, as long as there has been no intervening call to calloc, _expand, malloc, or realloc. If memblock points to a freed block, the block remains free after a call to _expand.

When the application is linked with a debug version of the C run-time libraries, _expand resolves to _expand_dbg. For more information about how the heap is managed during the debugging process, see Using C Run-Time Library Debugging Support.

Example

/* EXPAND.C */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

void main( void )
{
   char *bufchar;
   printf( "Allocate a 512 element buffer\n" );
   if( (bufchar = (char *)calloc( 512, sizeof( char ) )) == NULL )
      exit( 1 );
   printf( "Allocated %d bytes at %Fp\n",
         _msize( bufchar ), (void *)bufchar );
   if( (bufchar = (char *)_expand( bufchar, 1024 )) == NULL )
      printf( "Can't expand" );
   else
      printf( "Expanded block to %d bytes at %Fp\n",
            _msize( bufchar ), (void *)bufchar );
   /* Free memory */
   free( bufchar );
   exit( 0 );
}

Output

Allocate a 512 element buffer
Allocated 512 bytes at 002C12BC
Expanded block to 1024 bytes at 002C12BC

Memory Allocation Routines

See Also calloc, free, malloc, _msize, realloc


fabs

Calculates the absolute value of the floating-point argument.

double fabs( double x );

Function | Required Header | Compatibility
fabs | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fabs returns the absolute value of its argument. There is no error return.

Parameter

x

Floating-point value

Example

/* ABS.C: This program computes and displays
 * the absolute values of several numbers.
 */

#include  <stdio.h>
#include  <math.h>
#include  <stdlib.h>

void main( void )
{
   int    ix = -4, iy;
   long   lx = -41567L, ly;
   double dx = -3.141593, dy;

   iy = abs( ix );
   printf( "The absolute value of %d is %d\n", ix, iy);

   ly = labs( lx );
   printf( "The absolute value of %ld is %ld\n", lx, ly);

   dy = fabs( dx );
   printf( "The absolute value of %f is %f\n", dx, dy );
}

Output

The absolute value of -4 is 4
The absolute value of -41567 is 41567
The absolute value of -3.141593 is 3.141593

Floating-Point Support Routines

See Also abs, _cabs, labs


fclose, _fcloseall

Closes a stream (fclose) or closes all open streams (_fcloseall).

int fclose( FILE *stream );

int _fcloseall( void );

Function | Required Header | Compatibility
fclose | <stdio.h> | ANSI, Win 95, Win NT
_fcloseall | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fclose returns 0 if the stream is successfully closed. _fcloseall returns the total number of streams closed. Both functions return EOF to indicate an error.

Parameter

stream

Pointer to FILE structure

Remarks

The fclose function closes stream. _fcloseall closes all open streams except stdin, stdout, stderr (and, in MS-DOS®, _stdaux and _stdprn). It also closes and deletes any temporary files created by tmpfile. In both functions, all buffers associated with the stream are flushed prior to closing. System-allocated buffers are released when the stream is closed. Buffers assigned by the user with setbuf and setvbuf are not automatically released.

Example

/* FOPEN.C: This program opens files named "data"
 * and "data2".It  uses fclose to close "data" and
 * _fcloseall to close all remaining files.
 */

#include <stdio.h>

FILE *stream, *stream2;

void main( void )
{
   int numclosed;

   /* Open for read (will fail if file "data" does not exist) */
   if( (stream  = fopen( "data", "r" )) == NULL )
      printf( "The file 'data' was not opened\n" );
   else
      printf( "The file 'data' was opened\n" );

   /* Open for write */
   if( (stream2 = fopen( "data2", "w+" )) == NULL )
      printf( "The file 'data2' was not opened\n" );
   else
      printf( "The file 'data2' was opened\n" );

   /* Close stream */
   if( fclose( stream ) )
      printf( "The file 'data' was not closed\n" );

   /* All other files are closed: */
   numclosed = _fcloseall( );
   printf( "Number of files closed by _fcloseall: %u\n", numclosed );
}

Output

The file 'data' was opened
The file 'data2' was opened
Number of files closed by _fcloseall: 1

Stream I/O Routines

See Also _close, _fdopen, fflush, fopen, freopen


_fcvt

Converts a floating-point number to a string.

char *_fcvt( double value, int count, int *dec, int *sign );

Function | Required Header | Compatibility
_fcvt | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_fcvt returns a pointer to the string of digits. There is no error return.

Parameters

value

Number to be converted

count

Number of digits after decimal point

dec

Pointer to stored decimal-point position

sign

Pointer to stored sign indicator

Remarks

The _fcvt function converts a floating-point number to a null-terminated character string. The value parameter is the floating-point number to be converted. _fcvt stores the digits of value as a string and appends a null character ('\0'). The count parameter specifies the number of digits to be stored after the decimal point. Excess digits are rounded off to count places. If there are fewer than count digits of precision, the string is padded with zeros.

Only digits are stored in the string. The position of the decimal point and the sign of value can be obtained from dec and sign after the call. The dec parameter points to an integer value; this integer value gives the position of the decimal point with respect to the beginning of the string. A zero or negative integer value indicates that the decimal point lies to the left of the first digit. The parameter sign points to an integer indicating the sign of value. The integer is set to 0 if value is positive and is set to a nonzero number if value is negative.

_ecvt and _fcvt use a single statically allocated buffer for the conversion. Each call to one of these routines destroys the results of the previous call.

Example

/* FCVT.C: This program converts the constant
 * 3.1415926535 to a string and sets the pointer
 * *buffer to point to that string.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int  decimal, sign;
   char *buffer;
   double source = 3.1415926535;

   buffer = _fcvt( source, 7, &decimal, &sign );
   printf( "source: %2.10f   buffer: '%s'   decimal: %d   sign: %d\n",
            source, buffer, decimal, sign );
}

Output

source: 3.1415926535   buffer: '31415927'   decimal: 1   sign: 0

Data Conversion Routines | Floating-Point Support Routines

See Also atof, _ecvt, _gcvt


_fdopen, _wfdopen

Associate a stream with a file that was previously opened for low-level I/O.

FILE *_fdopen( int handle, const char *mode );

FILE *_wfdopen( int handle, const wchar_t *mode );

Function | Required Header | Compatibility
_fdopen | <stdio.h> | Win 95, Win NT
_wfdopen | <stdio.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the open stream. A null pointer value indicates an error.

Parameters

handle

Handle to open file

mode

Type of file access

Remarks

The _fdopen function associates an I/O stream with the file identified by handle, thus allowing a file opened for low-level I/O to be buffered and formatted. _wfdopen is a wide-character version of _fdopen; the mode argument to _wfdopen is a wide-character string. _wfdopen and _fdopen behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tfdopen | _fdopen | _fdopen | _wfdopen

The mode character string specifies the type of file and file access.

The character string mode specifies the type of access requested for the file, as follows:

"r"

Opens for reading. If the file does not exist or cannot be found, the fopen call fails.

"w"

Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"

Opens for writing at the end of the file (appending); creates the file first if it doesn’t exist.

"r+"

Opens for both reading and writing. (The file must exist.)

"w+"

Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"

Opens for reading and appending; creates the file first if it doesn’t exist.

When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. The file pointer can be repositioned using fseek or rewind, but is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten. When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for “update”). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired.

In addition to the above values, the following characters can be included in mode to specify the translation mode for newline characters:

t

Open in text (translated) mode. In this mode, carriage return–linefeed (CR-LF) combinations are translated into single linefeeds (LF) on input, and LF characters are translated to CR-LF combinations on output. Also, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing, fopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using the fseek and ftell functions to move within a file that ends with a CTRL+Z may cause fseek to behave improperly near the end of the file.

b

Open in binary (untranslated) mode; the above translations are suppressed.

c

Enable the commit flag for the associated filename so that the contents of the file buffer are written directly to disk if either fflush or _flushall is called.

n

Reset the commit flag for the associated filename to “no-commit.” This is the default. It also overrides the global commit flag if you link your program with COMMODE.OBJ. The global commit flag default is “no-commit” unless you explicitly link your program with COMMODE.OBJ.

The t, c, and n mode options are Microsoft extensions for fopen and _fdopen and should not be used where ANSI portability is desired.

If t or b is not given in mode, the default translation mode is defined by the global variable _fmode. If t or b is prefixed to the argument, the function fails and returns NULL. For a discussion of text and binary modes, see Text and Binary Mode File I/O.

Valid characters for the mode string used in fopen and _fdopen correspond to oflag arguments used in _open and _sopen, as follows.

Characters in mode String | Equivalent oflag Value for _open/_sopen
a | _O_WRONLY | _O_APPEND (usually _O_WRONLY | _O_CREAT | _O_APPEND)
a+ | _O_RDWR | _O_APPEND (usually _O_RDWR | _O_APPEND | _O_CREAT )
r | _O_RDONLY
r+ | _O_RDWR
w | _O_WRONLY (usually _O_WRONLY | _O_CREAT | _O_TRUNC)
w+ | _O_RDWR (usually _O_RDWR | _O_CREAT | _O_TRUNC)
b | _O_BINARY
t | _O_TEXT
c | None
n | None

Example

/* _FDOPEN.C: This program opens a file using low-
 * level I/O, then uses _fdopen to switch to stream
 * access. It counts the lines in the file.
 */

#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>

void main( void )
{
   FILE *stream;
   int  fh, count = 0;
   char inbuf[128];

   /* Open a file handle. */
   if( (fh = _open( "_fdopen.c", _O_RDONLY )) == -1 )
      exit( 1 );

   /* Change handle access to stream access. */
   if( (stream = _fdopen( fh, "r" )) == NULL )
      exit( 1 );

   while( fgets( inbuf, 128, stream ) != NULL )
      count++;

   /* After _fdopen, close with fclose, not _close. */
   fclose( stream );
   printf( "Lines in file: %d\n", count );
}

Output

Lines in file: 32

Stream I/O Routines

See Also _dup, fclose, fopen, freopen, _open


feof

Tests for end-of-file on a stream.

int feof( FILE *stream );

Function | Required Header | Compatibility
feof | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The feof function returns a nonzero value after the first read operation that attempts to read past the end of the file. It returns 0 if the current position is not end of file. There is no error return.

Parameter

stream

Pointer to FILE structure

Remarks

The feof routine (implemented both as a function and as a macro) determines whether the end of stream has been reached. When end of file is reached, read operations return an end-of-file indicator until the stream is closed or until rewind, fsetpos, fseek, or clearerr is called against it.

Example

/* FEOF.C: This program uses feof to indicate when
 * it reaches the end of the file FEOF.C. It also
 * checks for errors with ferror.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int  count, total = 0;
   char buffer[100];
   FILE *stream;

   if( (stream = fopen( "feof.c", "r" )) == NULL )
      exit( 1 );

   /* Cycle until end of file reached: */
   while( !feof( stream ) )
   {
      /* Attempt to read in 10 bytes: */
      count = fread( buffer, sizeof( char ), 100, stream );
      if( ferror( stream ) )      {
         perror( "Read error" );
         break;
      }

      /* Total up actual bytes read */
      total += count;
   }
   printf( "Number of bytes read = %d\n", total );
   fclose( stream );
}

Output

Number of bytes read = 745

Error Handling Routines | Stream I/O Routines

See Also clearerr, _eof, ferror, perror


ferror

Tests for an error on a stream.

int ferror( FILE *stream );

Function | Required Header | Compatibility
ferror | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If no error has occurred on stream, ferror returns 0. Otherwise, it returns a nonzero value.

Parameter

stream

Pointer to FILE structure

Remarks

The ferror routine (implemented both as a function and as a macro) tests for a reading or writing error on the file associated with stream. If an error has occurred, the error indicator for the stream remains set until the stream is closed or rewound, or until clearerr is called against it.

Example

/* FEOF.C: This program uses feof to indicate when
 * it reaches the end of the file FEOF.C. It also
 * checks for errors with ferror.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int  count, total = 0;
   char buffer[100];
   FILE *stream;

   if( (stream = fopen( "feof.c", "r" )) == NULL )
      exit( 1 );

   /* Cycle until end of file reached: */
   while( !feof( stream ) )
   {
      /* Attempt to read in 10 bytes: */
      count = fread( buffer, sizeof( char ), 100, stream );
      if( ferror( stream ) )      {
         perror( "Read error" );
         break;
      }

      /* Total up actual bytes read */
      total += count;
   }
   printf( "Number of bytes read = %d\n", total );
   fclose( stream );
}

Output

Number of bytes read = 745

Error Handling Routines | Stream I/O Routines

See Also clearerr, _eof, feof, fopen, perror


fflush

Flushes a stream.

int fflush( FILE *stream );

Function | Required Header | Compatibility
fflush | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fflush returns 0 if the buffer was successfully flushed. The value 0 is also returned in cases in which the specified stream has no buffer or is open for reading only. A return value of EOF indicates an error.

Note If fflush returns EOF, data may have been lost due to a write failure. When setting up a critical error handler, it is safest to turn buffering off with the setvbuf function or to use low-level I/O routines such as _open, _close, and _write instead of the stream I/O functions.

Parameter

stream

Pointer to FILE structure

Remarks

The fflush function flushes a stream. If the file associated with stream is open for output, fflush writes to that file the contents of the buffer associated with the stream. If the stream is open for input, fflush clears the contents of the buffer. fflush negates the effect of any prior call to ungetc against stream. Also, fflush(NULL) flushes all streams opened for output. The stream remains open after the call. fflush has no effect on an unbuffered stream.

Buffers are normally maintained by the operating system, which determines the optimal time to write the data automatically to disk: when a buffer is full, when a stream is closed, or when a program terminates normally without closing the stream. The commit-to-disk feature of the run-time library lets you ensure that critical data is written directly to disk rather than to the operating-system buffers. Without rewriting an existing program, you can enable this feature by linking the program’s object files with COMMODE.OBJ. In the resulting executable file, calls to _flushall write the contents of all buffers to disk. Only _flushall and fflush are affected by COMMODE.OBJ.

For information about controlling the commit-to-disk feature, see Stream I/O, fopen, and _fdopen.

Example

/* FFLUSH.C */

#include <stdio.h>
#include <conio.h>

void main( void )
{
   int integer;
   char string[81];

   /* Read each word as a string. */
   printf( "Enter a sentence of four words with scanf: " );
   for( integer = 0; integer < 4; integer++ )
   {
      scanf( "%s", string );
      printf( "%s\n", string );
   }

   /* You must flush the input buffer before using gets. */
   fflush( stdin );
   printf( "Enter the same sentence with gets: " );
   gets( string );
   printf( "%s\n", string );
}

Output

Enter a sentence of four words with scanf: This is a test
This
is
a
test
Enter the same sentence with gets: This is a test
This is a test

Stream I/O Routines

See Also fclose, _flushall, setvbuf


fgetc, fgetwc, _fgetchar, _fgetwchar

Read a character from a stream (fgetc, fgetwc) or stdin (_fgetchar, _fgetwchar).

int fgetc( FILE *stream );

wint_t fgetwc( FILE *stream );

int _fgetchar( void );

wint_t _fgetwchar( void );

Function | Required Header | Compatibility
fgetc | <stdio.h> | ANSI, Win 95, Win NT
fgetwc | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT
_fgetchar | <stdio.h> | Win 95, Win NT
_fgetwchar | <stdio.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fgetc and _fgetchar return the character read as an int or return EOF to indicate an error or end of file. fgetwc and _fgetwchar return, as a wint_t, the wide character that corresponds to the character read or return WEOF to indicate an error or end of file. For all four functions, use feof or ferror to distinguish between an error and an end-of-file condition. For fgetc and fgetwc, if a read error occurs, the error indicator for the stream is set.

Parameter

stream

Pointer to FILE structure

Remarks

Each of these functions reads a single character from the current position of a file; in the case of fgetc and fgetwc, this is the file associated with stream. The function then increments the associated file pointer (if defined) to point to the next character. If the stream is at end of file, the end-of-file indicator for the stream is set. Routine-specific remarks follow.

Routine | Remarks
fgetc | Equivalent to getc, but implemented only as a function, rather than as a function and a macro.
fgetwc | Wide-character version of fgetc. Reads c as a multibyte character or a wide character according to whether stream is opened in text mode or binary mode.
_fgetchar | Equivalent to fgetc( stdin ). Also equivalent to getchar, but implemented only as a function, rather than as a function and a macro. Microsoft-specific; not ANSI-compatible.
_fgetwchar | Wide-character version of _fgetchar. Reads c as a multibyte character or a wide character according to whether stream is opened in text mode or binary mode. Microsoft-specific; not ANSI-compatible.

For more information about processing wide characters and multibyte characters in text and binary modes, see Unicode Stream I/O in Text and Binary Modes.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_fgettc | fgetc | fgetc | fgetwc
_fgettchar | fgetchar | fgetchar | _fgetwchar

Example

/* FGETC.C: This program uses getc to read the first
 * 80 input characters (or until the end of input)
 * and place them into a string named buffer.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   FILE *stream;
   char buffer[81];
   int  i, ch;

   /* Open file to read line from: */
   if( (stream = fopen( "fgetc.c", "r" )) == NULL )
      exit( 0 );

   /* Read in first 80 characters and place them in "buffer": */
   ch = fgetc( stream );
   for( i=0; (i < 80 ) && ( feof( stream ) == 0 ); i++ )
   {
      buffer[i] = (char)ch;
      ch = fgetc( stream );
   }

   /* Add null to end string */
   buffer[i] = '\0';
   printf( "%s\n", buffer );
   fclose( stream );
}

Output

/* FGETC.C: This program uses getc to read the first
 * 80 input characters (or

Stream I/O Routines

See Also fputc, getc


fgetpos

Gets a stream’s file-position indicator.

int fgetpos( FILE *stream, fpos_t *pos );

Function | Required Header | Compatibility
fgetpos | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, fgetpos returns 0. On failure, it returns a nonzero value and sets errno to one of the following manifest constants (defined in STDIO.H): EBADF, which means the specified stream is not a valid file handle or is not accessible, or EINVAL, which means the stream value is invalid.

Parameters

stream

Target stream

pos

Position-indicator storage

Remarks

The fgetpos function gets the current value of the stream argument’s file-position indicator and stores it in the object pointed to by pos. The fsetpos function can later use information stored in pos to reset the stream argument’s pointer to its position at the time fgetpos was called. The pos value is stored in an internal format and is intended for use only by fgetpos and fsetpos.

Example

/* FGETPOS.C: This program opens a file and reads
 * bytes at several different locations.
 */

#include <stdio.h>

void main( void )
{
   FILE   *stream;
   fpos_t pos;
   char   buffer[20];

   if( (stream = fopen( "fgetpos.c", "rb" )) == NULL )
      printf( "Trouble opening file\n" );
   else
   {
      /* Read some data and then check the position. */
      fread( buffer, sizeof( char ), 10, stream );
      if( fgetpos( stream, &pos ) != 0 )
         perror( "fgetpos error" );
      else
      {
         fread( buffer, sizeof( char ), 10, stream );
         printf( "10 bytes at byte %ld: %.10s\n", pos, buffer );
      }

   /* Set a new position and read more data */
   pos = 140;
   if( fsetpos( stream, &pos ) != 0 )
      perror( "fsetpos error" );

   fread( buffer, sizeof( char ), 10, stream );
   printf( "10 bytes at byte %ld: %.10s\n", pos, buffer );
   fclose( stream );
   }
}

Output

10 bytes at byte 10: .C: This p
10 bytes at byte 140:
{
   FIL

Stream I/O Routines

See Also fsetpos


fgets, fgetws

Get a string from a stream.

char *fgets( char *string, int n, FILE *stream );

wchar_t *fgetws( wchar_t *string, int n, FILE *stream );

Function | Required Header | Compatibility
fgets | <stdio.h> | ANSI, Win 95, Win NT
fgetws | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns string. NULL is returned to indicate an error or an end-of-file condition. Use feof or ferror to determine whether an error occurred.

Parameters

string

Storage location for data

n

Maximum number of characters to read

stream

Pointer to FILE structure

Remarks

The fgets function reads a string from the input stream argument and stores it in string. fgets reads characters from the current stream position to and including the first newline character, to the end of the stream, or until the number of characters read is equal to n – 1, whichever comes first. The result stored in string is appended with a null character. The newline character, if read, is included in the string.

fgets is similar to the gets function; however, gets replaces the newline character with NULL. fgetws is a wide-character version of fgets.

fgetws reads the wide-character argument string as a multibyte-character string or a wide-character string according to whether stream is opened in text mode or binary mode, respectively. For more information about using text and binary modes in Unicode and multibyte stream-I/O, see Text and Binary Mode File I/O and Unicode Stream I/O in Text and Binary Modes.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_fgetts | fgets | fgets | fgetws

Example

/* FGETS.C: This program uses fgets to display
 * a line from a file on the screen.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char line[100];

   if( (stream = fopen( "fgets.c", "r" )) != NULL )
   {
      if( fgets( line, 100, stream ) == NULL)
         printf( "fgets error\n" );
      else
         printf( "%s", line);
      fclose( stream );
   }
}

Output

/* FGETS.C: This program uses fgets to display

Stream I/O Routines

See Also fputs, gets, puts


_filelength, _filelengthi64

Get the length of a file.

long _filelength( int handle );

__int64 _filelengthi64( int handle );

Function | Required Header | Compatibility
_filelength | <io.h> | Win 95, Win NT
_filelengthi64 | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Both _filelength and _filelengthi64 return the file length, in bytes, of the target file associated with handle. Both functions return a value of –1L to indicate an error, and an invalid handle sets errno to EBADF.

Parameter

handle

Target file handle

Example

/* CHSIZE.C: This program uses _filelength to report the size
 * of a file before and after modifying it with _chsize.
 */

#include <io.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

void main( void )
{
   int fh, result;
   unsigned int nbytes = BUFSIZ;

   /* Open a file */
   if( (fh = _open( "data", _O_RDWR | _O_CREAT, _S_IREAD
                   | _S_IWRITE ))  != -1 )
   {
      printf( "File length before: %ld\n", _filelength( fh ) );
      if( ( result = _chsize( fh, 329678 ) ) == 0 )
         printf( "Size successfully changed\n" );
      else
         printf( "Problem in changing the size\n" );
      printf( "File length after:  %ld\n", _filelength( fh ) );
      _close( fh );
   }
}

Output

File length before: 0
Size successfully changed
File length after:  329678

File Handling Routines

See Also _chsize, _fileno, _fstat, _fstati64, _stat, _stati64


_fileno

Gets the file handle associated with a stream.

int _fileno( FILE *stream );

Function | Required Header | Compatibility
_fileno | <stdio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_fileno returns the file handle. There is no error return. The result is undefined if stream does not specify an open file.

Parameter

stream

Pointer to FILE structure

Remarks

The _fileno routine returns the file handle currently associated with stream. This routine is implemented both as a function and as a macro. For details on choosing either implementation, see Choosing Between Functions and Macros.

Example

/* FILENO.C: This program uses _fileno to obtain
 * the file handle for some standard C streams.
 */

#include <stdio.h>

void main( void )
{
   printf( "The file handle for stdin is %d\n", _fileno( stdin ) );
   printf( "The file handle for stdout is %d\n", _fileno( stdout ) );
   printf( "The file handle for stderr is %d\n", _fileno( stderr ) );
}

Output

The file handle for stdin is 0
The file handle for stdout is 1
The file handle for stderr is 2

Stream I/O Routines

See Also _fdopen, _filelength, fopen, freopen


_find, _wfind Functions

These functions search for and close searches for specified filenames.

  • _findclose

  • _findnext, _findnexti64, _wfindnext, _wfindnexti64

  • _findfirst, _findfirsti64, _wfindfirst, _wfindfirsti64

Remarks

The _findfirst function provides information about the first instance of a filename that matches the file specified in the filespec argument. Any wildcard combination supported by the host operating system can be used in filespec. File information is returned in a _finddata_t structure, defined in IO.H. The _finddata_t structure includes the following elements:

unsigned attrib

File attribute

time_t time_create

Time of file creation ( –1L for FAT file systems)

time_t time_access

Time of last file access (–1L for FAT file systems)

time_t time_write

Time of last write to file

_fsize_t size

Length of file in bytes

char name[_MAX_FNAME]

Null-terminated name of matched file/directory, without the path

In file systems that do not support the creation and last access times of a file, such as the FAT system, the time_create and time_access fields are always –1L.

_MAX_FNAME is defined in STDLIB.H as 256 bytes.

You cannot specify target attributes (such as _A_RDONLY) by which to limit the find operation. This attribute is returned in the attrib field of the _finddata_t structure and can have the following values (defined in IO.H).

_A_ARCH

Archive. Set whenever the file is changed, and cleared by the BACKUP command. Value: 0x20

_A_HIDDEN

Hidden file. Not normally seen with the DIR command, unless the /AH option is used. Returns information about normal files as well as files with this attribute. Value: 0x02

_A_NORMAL

Normal. File can be read or written to without restriction. Value: 0x00

_A_RDONLY

Read-only. File cannot be opened for writing, and a file with the same name cannot be created. Value: 0x01

_A_SUBDIR

Subdirectory. Value: 0x10

_A_SYSTEM

System file. Not normally seen with the DIR command, unless the /A or /A:S option is used. Value: 0x04

_findnext finds the next name, if any, that matches the filespec argument specified in a prior call to _findfirst. The fileinfo argument should point to a structure initialized by a previous call to _findfirst. If a match is found, the fileinfo structure contents are altered as described above. _findclose closes the specified search handle and releases all associated resources for both _findfirst and _findnext. The handle returned by either _findfirst or _findnext must first be passed to _findclose, before modification operations, such as deleting, can be performed on the directories that form the paths passed to them.

The _find functions allow nested calls. For example, if the file found by a call to _findfirst or _findnext is a subdirectory, a new search can be initiated with another call to _findfirst or _findnext.

_wfindfirst and _wfindnext are wide-character versions of _findfirst and _findnext. The structure argument of the wide-character versions has the _wfinddata_t data type, which is defined in IO.H and in WCHAR.H. The fields of this data type are the same as those of the _finddata_t data type, except that in _wfinddata_t the name field is of type wchar_t rather than type char. Otherwise _wfindfirst and _wfindnext behave identically to _findfirst and _findnext. Functions _findfirsti64, _findnexti64, _wfindfirsti64, and _wfindnexti64 also behave identically except they use and return 64-bit file lengths.

Example

/* FFIND.C: This program uses the 32-bit _find functions to print
 * a list of all files (and their attributes) with a .C extension
 * in the current directory.
 */

#include <stdio.h>
#include <io.h>
#include <time.h>

void main( void )
{
    struct _finddata_t c_file;
    long hFile;

    /* Find first .c file in current directory */
    if( (hFile = _findfirst( "*.c", &c_file )) == -1L )
       printf( "No *.c files in current directory!\n" );
   else
   {
            printf( "Listing of .c files\n\n" );
            printf( "\nRDO HID SYS ARC  FILE         DATE %25c SIZE\n", ' ' );
            printf( "--- --- --- ---  ----         ---- %25c ----\n", ' ' );
            printf( ( c_file.attrib & _A_RDONLY ) ? " Y  " : " N  " );
            printf( ( c_file.attrib & _A_SYSTEM ) ? " Y  " : " N  " );
            printf( ( c_file.attrib & _A_HIDDEN ) ? " Y  " : " N  " );
            printf( ( c_file.attrib & _A_ARCH )   ? " Y  " : " N  " );
            printf( " %-12s %.24s  %9ld\n",
               c_file.name, ctime( &( c_file.time_write ) ), c_file.size );

            /* Find the rest of the .c files */
            while( _findnext( hFile, &c_file ) == 0 )
            {
                printf( ( c_file.attrib & _A_RDONLY ) ? " Y  " : " N  " );
                printf( ( c_file.attrib & _A_SYSTEM ) ? " Y  " : " N  " );
                printf( ( c_file.attrib & _A_HIDDEN ) ? " Y  " : " N  " );
                printf( ( c_file.attrib & _A_ARCH )   ? " Y  " : " N  " );
                printf( " %-12s %.24s  %9ld\n",
                   c_file.name, ctime( &( c_file.time_write ) ), c_file.size );
            }

       _findclose( hFile );
   }
}

Output

Listing of .c files

RDO HID SYS ARC  FILE         DATE                           SIZE
--- --- --- ---  ----         ----                           ----
 N   N   N   Y   CWAIT.C      Tue Jun 01 04:07:26 1993       1611
 N   N   N   Y   SPRINTF.C    Thu May 27 04:59:18 1993        617
 N   N   N   Y   CABS.C       Thu May 27 04:58:46 1993        359
 N   N   N   Y   BEGTHRD.C    Tue Jun 01 04:00:48 1993       3726

System Calls Routines


_findclose

Closes the specified search handle and releases associated resources.

int _findclose( long handle );

Function | Required Header | Compatibility
_findclose | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _findclose returns 0. Otherwise, it returns –1 and sets errno to ENOENT, indicating that no more matching files could be found.

Parameter

handle

Search handle returned by a previous call to _findfirst


_findfirst, _findfirsti64, _wfindfirst, _wfindfirsti64

Provides information about the first instance of a filename that matches the file specified in the filespec argument.

long _findfirst( char *filespec, struct _finddata_t *fileinfo );

__int64 _findfirsti64( char *filespec, struct _finddata_t *fileinfo );

long _wfindfirst( wchar_t *filespec, struct _wfinddata_t *fileinfo );

__int64 _wfindfirsti64( wchar_t *filespec, struct _wfinddata_t *fileinfo );

Function | Required Header | Compatibility
_findfirst | <io.h> | Win 95, Win NT
_findfirsti64 | <io.h> | Win 95, Win NT
_wfindfirst | <io.h> or <wchar.h> | Win NT
_wfindfirsti64 | <io.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _findfirst and _wfindfirst return a unique search handle identifying the file or group of files matching the filespec specification, which can be used in a subsequent call to _findnext or _wfindnext, respectively, or to _findclose. Otherwise, _findfirst and _wfindfirst return –1 and set errno to one of the following values:

ENOENT

File specification that could not be matched

EINVAL

Invalid filename specification

Parameters

filespec

Target file specification (may include wildcards)

fileinfo

File information buffer

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tfindfirst | _findfirst | _findfirst | _wfindfirst
_tfindfirsti64 | _findfirsti64 | _findfirsti64 | _wfindfirsti64


_findnext, _findnexti64, _wfindnext, _wfindnexti64

Find the next name, if any, that matches the filespec argument in a previous call to _findfirst, and then alters the fileinfo structure contents accordingly.

int _findnext( long handle, struct _finddata_t *fileinfo );

__int64 _findnexti64( long handle, struct _finddata_t *fileinfo );

int _wfindnext( long handle, struct _wfinddata_t *fileinfo );

__int64 _wfindnexti64( long handle, struct _wfinddata_t *fileinfo );

Function | Required Header | Compatibility
_findnext | <io.h> | Win 95, Win NT
_findnexti64 | <io.h> | Win 95, Win NT
_wfindnext | <io.h> or <wchar.h> | Win NT
_wfindnexti64 | <io.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _findnext and _wfindnext return 0. Otherwise, they return –1 and set errno to ENOENT, indicating that no more matching files could be found.

Parameters

handle

Search handle returned by a previous call to _findfirst

fileinfo

File information buffer

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tfindnext | _findnext | _findnext | _wfindnext
_tfindnexti64 | _findnexti64 | _findnexti64 | _wfindnexti64


_finite

Determines whether given double-precision floating point value is finite.

int _finite( double x );

Function | Required Header | Compatibility
_finite | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_finite returns a nonzero value (TRUE) if its argument x is not infinite, that is, if –INF < x < +INF. It returns 0 (FALSE) if the argument is infinite or a NaN.

Parameter

x

Double-precision floating-point value

Floating-Point Support Routines

See Also _isnan, _fpclass


floor

Calculates the floor of a value.

double floor( double x );

Function | Required Header | Compatibility
floor | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The floor function returns a floating-point value representing the largest integer that is less than or equal to x.There is no error return.

Parameter

x

Floating-point value

Example

/* FLOOR.C: This example displays the largest integers
 * less than or equal to the floating-point values 2.8
 * and -2.8. It then shows the smallest integers greater
 * than or equal to 2.8 and -2.8.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double y;

   y = floor( 2.8 );
   printf( "The floor of 2.8 is %f\n", y );
   y = floor( -2.8 );
   printf( "The floor of -2.8 is %f\n", y );

   y = ceil( 2.8 );
   printf( "The ceil of 2.8 is %f\n", y );
   y = ceil( -2.8 );
   printf( "The ceil of -2.8 is %f\n", y );
}

Output

The floor of 2.8 is 2.000000
The floor of -2.8 is -3.000000
The ceil of 2.8 is 3.000000
The ceil of -2.8 is -2.000000

Floating-Point Support Routines

See Also ceil, fmod


_flushall

Flushes all streams; clears all buffers.

int _flushall( void );

Function | Required Header | Compatibility
_flushall | <stdio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_flushall returns the number of open streams (input and output). There is no error return.

Remarks

By default, the _flushall function writes to appropriate files the contents of all buffers associated with open output streams. All buffers associated with open input streams are cleared of their current contents. (These buffers are normally maintained by the operating system, which determines the optimal time to write the data automatically to disk: when a buffer is full, when a stream is closed, or when a program terminates normally without closing streams.)

If a read follows a call to _flushall, new data is read from the input files into the buffers. All streams remain open after the call to _flushall.

The commit-to-disk feature of the run-time library lets you ensure that critical data is written directly to disk rather than to the operating system buffers. Without rewriting an existing program, you can enable this feature by linking the program’s object files with COMMODE.OBJ. In the resulting executable file, calls to _flushall write the contents of all buffers to disk. Only _flushall and fflush are affected by COMMODE.OBJ.

For information about controlling the commit-to-disk feature, see Stream I/O, fopen, and _fdopen.

Example

/* FLUSHALL.C: This program uses _flushall
 * to flush all open buffers.
 */

#include <stdio.h>

void main( void )
{
   int numflushed;

   numflushed = _flushall();
   printf( "There were %d streams flushed\n", numflushed );
}

Output

There were 3 streams flushed

Stream I/O Routines

See Also _commit, fclose, fflush, _flushall, setvbuf


fmod

Calculates the floating-point remainder.

double fmod( double x, double y );

Function | Required Header | Compatibility
fmod | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fmod returns the floating-point remainder of x / y. If the value of y is 0.0, fmod returns a quiet NaN. For information about representation of a quiet NaN by the printf family, see printf.

Parameters

x, y

Floating-point values

Remarks

The fmod function calculates the floating-point remainder f of x / y such that x = i * y + f, where i is an integer, f has the same sign as x, and the absolute value of f is less than the absolute value of y.

Example

/* FMOD.C: This program displays a
 * floating-point remainder.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double w = -10.0, x = 3.0, y = 0.0, z;

   z = fmod( x, y );
   printf( "The remainder of %.2f / %.2f is %f\n", w, x, z );
   printf( "The remainder of %.2f / %.2f is %f\n", x, y, z );

}

Output

The remainder of -10.00 / 3.00 is -1.000000

Floating-Point Support Routines

See Also ceil, fabs, floor


fopen, _wfopen

Open a file.

FILE *fopen( const char *filename, const char *mode );

FILE *_wfopen( const wchar_t *filename, const wchar_t *mode );

Function | Required Header | Compatibility
fopen | <stdio.h> | ANSI, Win 95, Win NT
_wfopen | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

The c, n, and t mode options are Microsoft extensions for fopen and _fdopen and should not be used where ANSI portability is desired.

Return Value

Each of these functions returns a pointer to the open file. A null pointer value indicates an error.

Parameters

filename

Filename

mode

Type of access permitted

Remarks

The fopen function opens the file specified by filename. _wfopen is a wide-character version of fopen; the arguments to _wfopen are wide-character strings. _wfopen and fopen behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tfopen | fopen | fopen | _wfopen

The character string mode specifies the type of access requested for the file, as follows:

"r"

Opens for reading. If the file does not exist or cannot be found, the fopen call fails.

"w"

Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"

Opens for writing at the end of the file (appending) without removing the EOF marker before writing new data to the file; creates the file first if it doesn’t exist.

"r+"

Opens for both reading and writing. (The file must exist.)

"w+"

Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"

Opens for reading and appending; the appending operation includes the removal of the EOF marker before new data is written to the file and the EOF marker is restored after writing is complete; creates the file first if it doesn’t exist.

When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. The file pointer can be repositioned using fseek or rewind, but is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten.

The "a" mode does not remove the EOF marker before appending to the file. After appending has occurred, the MS-DOS TYPE command only shows data up to the original EOF marker and not any data appended to the file. The "a+" mode does remove the EOF marker before appending to the file. After appending, the MS-DOS TYPE command shows all data in the file. The "a+" mode is required for appending to a stream file that is terminated with the CTRL+Z EOF marker.

When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for “update”). However, when you switch between reading and writing, there must be an intervening fflush, fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired.

In addition to the above values, the following characters can be included in mode to specify the translation mode for newline characters:

t

Open in text (translated) mode. In this mode, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing with "a+", fopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using fseek and ftell to move within a file that ends with a CTRL+Z, may cause fseek to behave improperly near the end of the file.

Also, in text mode, carriage return–linefeed combinations are translated into single linefeeds on input, and linefeed characters are translated to carriage return–linefeed combinations on output. When a Unicode stream-I/O function operates in text mode (the default), the source or destination stream is assumed to be a sequence of multibyte characters. Therefore, the Unicode stream-input functions convert multibyte characters to wide characters (as if by a call to the mbtowc function). For the same reason, the Unicode stream-output functions convert wide characters to multibyte characters (as if by a call to the wctomb function).

b

Open in binary (untranslated) mode; translations involving carriage-return and linefeed characters are suppressed.

If t or b is not given in mode, the default translation mode is defined by the global variable _fmode. If t or b is prefixed to the argument, the function fails and returns NULL.

For more information about using text and binary modes in Unicode and multibyte stream-I/O, see Text and Binary Mode File I/O and Unicode Stream I/O in Text and Binary Modes.

c

Enable the commit flag for the associated filename so that the contents of the file buffer are written directly to disk if either fflush or _flushall is called.

n

Reset the commit flag for the associated filename to “no-commit.” This is the default. It also overrides the global commit flag if you link your program with COMMODE.OBJ. The global commit flag default is “no-commit” unless you explicitly link your program with COMMODE.OBJ.

Valid characters for the mode string used in fopen and _fdopen correspond to oflag arguments used in _open and _sopen, as follows.

Characters in mode String | Equivalent oflag Value for _open/_sopen
a | _O_WRONLY | _O_APPEND (usually _O_WRONLY | _O_CREAT | _O_APPEND)
a+ | _O_RDWR | _O_APPEND (usually _O_RDWR | _O_APPEND | _O_CREAT )
r | _O_RDONLY
r+ | _O_RDWR
w | _O_WRONLY (usually _O_WRONLY | _O_CREAT | _O_TRUNC)
w+ | _O_RDWR (usually _O_RDWR | _O_CREAT | _O_TRUNC)
b | _O_BINARY
t | _O_TEXT
c | None
n | None

Example

/* FOPEN.C: This program opens files named "data"
 * and "data2".It  uses fclose to close "data" and
 * _fcloseall to close all remaining files.
 */

#include <stdio.h>

FILE *stream, *stream2;

void main( void )
{
   int numclosed;

   /* Open for read (will fail if file "data" does not exist) */
   if( (stream  = fopen( "data", "r" )) == NULL )
      printf( "The file 'data' was not opened\n" );
   else
      printf( "The file 'data' was opened\n" );

   /* Open for write */
   if( (stream2 = fopen( "data2", "w+" )) == NULL )
      printf( "The file 'data2' was not opened\n" );
   else
      printf( "The file 'data2' was opened\n" );

   /* Close stream */
   if( fclose( stream ) )
      printf( "The file 'data' was not closed\n" );

   /* All other files are closed: */
   numclosed = _fcloseall( );
   printf( "Number of files closed by _fcloseall: %u\n", numclosed );
}

Output

The file 'data' was opened
The file 'data2' was opened
Number of files closed by _fcloseall: 1

Stream I/O Routines

See Also fclose, _fdopen, ferror, _fileno, freopen, _open, _setmode


_fpclass

Returns status word containing information on floating-point class.

int _fpclass( double

x );

Function | Required Header | Compatibility
_fpclass | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_fpclass returns an integer value that indicates the floating-point class of its argument x. The status word may have one of the following values, defined in FLOAT.H.

Value | Meaning
_FPCLASS_SNAN | Signaling NaN
_FPCLASS_QNAN | Quiet NaN
_FPCLASS_NINF | Negative infinity ( –INF)
_FPCLASS_NN | Negative normalized non-zero
_FPCLASS_ND | Negative denormalized
_FPCLASS_NZ | Negative zero ( – 0)
_FPCLASS_PZ | Positive 0 (+0)
_FPCLASS_PD | Positive denormalized
_FPCLASS_PN | Positive normalized non-zero
_FPCLASS_PINF | Positive infinity (+INF)

Parameter

x

Double-precision floating-point value

Floating-Point Support Routines

See Also _isnan


_fpieee_flt

Invokes user-defined trap handler for IEEE floating-point exceptions.

int _fpieee_flt( unsigned long exc_code, struct _EXCEPTION_POINTERS *exc_info, int handler(_FPIEEE_RECORD *) );

Function | Required Header | Compatibility
_fpieee_flt | <fpieee.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value of _fpieee_flt is the value returned by handler. As such, the IEEE filter routine may be used in the except clause of a structured exception-handling (SEH) mechanism.

Parameters

exc_code

Exception code

exc_info

Pointer to the Windows NT exception information structure

handler

Pointer to user’s IEEE trap-handler routine

Remarks

The _fpieee_flt function invokes a user-defined trap handler for IEEE floating-point exceptions and provides it with all relevant information. This routine serves as an exception filter in the SEH mechanism, which invokes your own IEEE exception handler when necessary.

The _FPIEEE_RECORD structure, defined in FPIEEE.H, contains information pertaining to an IEEE floating-point exception. This structure is passed to the user-defined trap handler by _fpieee_flt.

_FPIEEE_RECORD Field | Description
unsigned int RoundingMode, unsigned int Precision | These fields contain information on the floating-point environment at the time the exception occurred.
unsigned int Operation | Indicates the type of operation that caused the trap. If the type is a comparison (_FpCodeCompare), you can supply one of the special _FPIEEE_COMPARE_RESULT values (as defined in FPIEEE.H) in the Result.Value field. The conversion type (_FpCodeConvert) indicates that the trap occurred during a floating-point conversion operation. You can look at the Operand1 and Result types to determine the type of conversion being attempted.
_FPIEEE_VALUE Operand1, _FPIEEE_VALUE Operand2, _FPIEEE_VALUE Result | These structures indicate the types and values of the proposed result and operands: OperandValid Flag indicating whether the responding value is valid. Format Data type of the corresponding value. The format type may be returned even if the corresponding value is not valid. Value Result or operand data value.

Example

/* FPIEEE.C: This program demonstrates the implementation of
 * a user-defined floating-point exception handler using the
 * _fpieee_flt function.
 */

#include <fpieee.h>
#include <excpt.h>
#include <float.h>

int fpieee_handler( _FPIEEE_RECORD * );

int fpieee_handler( _FPIEEE_RECORD *pieee )
{
   // user-defined ieee trap handler routine:
   // there is one handler for all
   // IEEE exceptions

   // Assume the user wants all invalid
   // operations to return 0.

   if ((pieee->Cause.InvalidOperation) &&
       (pieee->Result.Format == _FpFormatFp32))
   {
        pieee->Result.Value.Fp32Value = 0.0F;

        return EXCEPTION_CONTINUE_EXECUTION;
   }
   else
      return EXCEPTION_EXECUTE_HANDLER;
}

#define _EXC_MASK    \
    _EM_UNDERFLOW  + \
    _EM_OVERFLOW   + \
    _EM_ZERODIVIDE + \
    _EM_INEXACT

void main( void )
{
   // ...

   __try {
      // unmask invalid operation exception
      _controlfp(_EXC_MASK, _MCW_EM);

      // code that may generate
      // fp exceptions goes here
   }
   __except ( _fpieee_flt( GetExceptionCode(),
                GetExceptionInformation(),
                fpieee_handler ) ){

      // code that gets control

      // if fpieee_handler returns
      // EXCEPTION_EXECUTE_HANDLER goes here

   }

   // ...
}

Floating-Point Support Routines

See Also _control87


_fpreset

Resets the floating-point package.

void _fpreset( void );

Function | Required Header | Compatibility
_fpreset | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Remarks

The _fpreset function reinitializes the floating-point math package. _fpreset is usually used with signal, system, or the _exec or _spawn functions. If a program traps floating-point error signals (SIGFPE) with signal, it can safely recover from floating-point errors by invoking _fpreset and using longjmp.

Example

/* FPRESET.C: This program uses signal to set up a
 * routine for handling floating-point errors.
 */

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>

#pragma warning(disable : 4113) /* C4113 warning expected */

jmp_buf mark;              /* Address for long jump to jump to */
int     fperr;             /* Global error number */

void __cdecl fphandler( int sig, int num );   /* Prototypes */
void fpcheck( void );

void main( void )
{
   double n1, n2, r;
   int jmpret;
   /* Unmask all floating-point exceptions. */
    _control87( 0, _MCW_EM );
   /* Set up floating-point error handler. The compiler
    * will generate a warning because it expects
    * signal-handling functions to take only one argument.
    */
    if( signal( SIGFPE, fphandler ) == SIG_ERR )

   {
      fprintf( stderr, "Couldn't set SIGFPE\n" );
      abort();   }

   /* Save stack environment for return in case of error. First
    * time through, jmpret is 0, so true conditional is executed.
    * If an error occurs, jmpret will be set to -1 and false
    * conditional will be executed.
    */
   jmpret = setjmp( mark );
   if( jmpret == 0 )
   {
      printf( "Test for invalid operation - " );
      printf( "enter two numbers: " );
      scanf( "%lf %lf", &n1, &n2 );
      r = n1 / n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g / %4.3g = %4.3g\n", n1, n2, r );

      r = n1 * n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g * %4.3g = %4.3g\n", n1, n2, r );
   }
   else
      fpcheck();
}
/* fphandler handles SIGFPE (floating-point error) interrupt. Note
 * that this prototype accepts two arguments and that the
 * prototype for signal in the run-time library expects a signal
 * handler to have only one argument.
 *
 * The second argument in this signal handler allows processing of
 * _FPE_INVALID, _FPE_OVERFLOW, _FPE_UNDERFLOW, and
 * _FPE_ZERODIVIDE, all of which are Microsoft-specific symbols
 * that augment the information provided by SIGFPE. The compiler
 * will generate a warning, which is harmless and expected.

 */
void fphandler( int sig, int num )
{
   /* Set global for outside check since we don't want
    * to do I/O in the handler.
    */
   fperr = num;
   /* Initialize floating-point package. */
   _fpreset();
   /* Restore calling environment and jump back to setjmp. Return
    * -1 so that setjmp will return false for conditional test.
    */
   longjmp( mark, -1 );
}
void fpcheck( void )
{
   char fpstr[30];
   switch( fperr )
   {
   case _FPE_INVALID:
       strcpy( fpstr, "Invalid number" );
       break;
   case _FPE_OVERFLOW:
       strcpy( fpstr, "Overflow" );

       break;
   case _FPE_UNDERFLOW:
       strcpy( fpstr, "Underflow" );
       break;
   case _FPE_ZERODIVIDE:
       strcpy( fpstr, "Divide by zero" );
       break;
   default:
       strcpy( fpstr, "Other floating point error" );
       break;
   }
   printf( "Error %d: %s\n", fperr, fpstr );
}

Output

Test for invalid operation - enter two numbers: 5 0
Error 131: Divide by zero

Floating-Point Support Routines

See Also _exec Function Overview, signal, _spawn Function Overview, system


fprintf, fwprintf

Print formatted data to a stream.

int fprintf( FILE *stream, const char *format [, argument ]...);

int fwprintf( FILE *stream, const wchar_t *format [, argument ]...);

Function | Required Header | Compatibility
fprintf | <stdio.h> | ANSI, Win 95, Win NT
fwprintf | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fprintf returns the number of bytes written. fwprintf returns the number of wide characters written. Each of these functions returns a negative value instead when an output error occurs.

Parameters

stream

Pointer to FILE structure

format

Format-control string

argument

Optional arguments

Remarks

fprintf formats and prints a series of characters and values to the output stream. Each function argument (if any) is converted and output according to the corresponding format specification in format. For fprintf, the format argument has the same syntax and use that it has in printf.

fwprintf is a wide-character version of fprintf; in fwprintf, format is a wide-character string. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_ftprintf | fprintf | fprintf | fwprintf

For more information, see Format Specifcations.

Example

/* FPRINTF.C: This program uses fprintf to format various
 * data and print it to the file named FPRINTF.OUT. It
 * then displays FPRINTF.OUT on the screen using the system
 * function to invoke the operating-system TYPE command.
 */

#include <stdio.h>
#include <process.h>

FILE *stream;

void main( void )
{
   int    i = 10;
   double fp = 1.5;
   char   s[] = "this is a string";
   char   c = '\n';

   stream = fopen( "fprintf.out", "w" );
   fprintf( stream, "%s%c", s, c );
   fprintf( stream, "%d\n", i );
   fprintf( stream, "%f\n", fp );
   fclose( stream );
   system( "type fprintf.out" );
}

Output

this is a string
10
1.500000

Stream I/O Routines

See Also _cprintf, fscanf, sprintf


fputc, fputwc, _fputchar, _fputwchar

Writes a character to a stream (fputc, fputwc) or to stdout (_fputchar, _fputwchar).

int fputc( int c, FILE *stream );

wint_t fputwc( wint_t c, FILE *stream );

int _fputchar( int c );

wint_t _fputwchar( wint_t c );

Function | Required Header | Compatibility
fputc | <stdio.h> | ANSI, Win 95, Win NT
fputwc | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT
_fputchar | <stdio.h> | Win 95, Win NT
_fputwchar | <stdio.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the character written. For fputc and _fputchar, a return value of EOF indicates an error. For fputwc and _fputwchar, a return value of WEOF indicates an error.

Parameters

c

Character to be written

stream

Pointer to FILE structure

Remarks

Each of these functions writes the single character c to a file at the position indicated by the associated file position indicator (if defined) and advances the indicator as appropriate. In the case of fputc and fputwc, the file is associated with stream. If the file cannot support positioning requests or was opened in append mode, the character is appended to the end of the stream. Routine-specific remarks follow.

Routine | Remarks
fputc | Equivalent to putc, but implemented only as a function, rather than as a function and a macro.
fputwc | Wide-character version of fputc. Writes c as a multibyte character or a wide character according to whether stream is opened in text mode or binary mode.
_fputchar | Equivalent to fputc( stdout ). Also equivalent to putchar, but implemented only as a function, rather than as a function and a macro. Microsoft-specific; not ANSI-compatible.
_fputwchar | Wide-character version of _fputchar. Writes c as a multibyte character or a wide character according to whether stream is opened in text mode or binary mode. Microsoft-specific; not ANSI-compatible.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_fputtc | fputc | fputc | fputwc
_fputtchar | _fputchar | _fputchar | _fputwchar

Example

/* FPUTC.C: This program uses fputc and _fputchar
 * to send a character array to stdout.
 */

#include <stdio.h>

void main( void )
{
   char strptr1[] = "This is a test of fputc!!\n";
   char strptr2[] = "This is a test of _fputchar!!\n";
   char *p;

   /* Print line to stream using fputc. */
   p = strptr1;
   while( (*p != '\0') && fputc( *(p++), stdout ) != EOF ) ;

   /* Print line to stream using _fputchar. */
   p = strptr2;
   while( (*p != '\0') && _fputchar( *(p++) ) != EOF )
      ;
}

Stream I/O Routines

See Also fgetc, putc


fputs, fputws

Write a string to a stream.

int fputs( const char *string, FILE *stream );

int fputws( const wchar_t *string, FILE *stream );

Function | Required Header | Compatibility
fputs | <stdio.h> | ANSI, Win 95, Win NT
fputws | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a nonnegative value if it is successful. On an error, fputs returns EOF, and fputws returns WEOF.

Parameters

string

Output string

stream

Pointer to FILE structure

Remarks

Each of these functions copies string to the output stream at the current position. fputws copies the wide-character argument string to stream as a multibyte-character string or a wide-character string according to whether stream is opened in text mode or binary mode, respectively. Neither function copies the terminating null character.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_fputts | fputs | fputs | fputws

Example

/* FPUTS.C: This program uses fputs to write
 * a single line to the stdout stream.
 */

#include <stdio.h>

void main( void )
{
   fputs( "Hello world from fputs.\n", stdout );
}

Output

Hello world from fputs.

Stream I/O Routines

See Also fgets, gets, puts, _putws


fread

Reads data from a stream.

size_t fread( void *buffer, size_t size, size_t count, FILE *stream );

Function | Required Header | Compatibility
fread | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fread returns the number of full items actually read, which may be less than count if an error occurs or if the end of the file is encountered before reaching count. Use the feof or ferror function to distinguish a read error from an end-of-file condition. If size or count is 0, fread returns 0 and the buffer contents are unchanged.

Parameters

buffer

Storage location for data

size

Item size in bytes

count

Maximum number of items to be read

stream

Pointer to FILE structure

Remarks

The fread function reads up to count items of size bytes from the input stream and stores them in buffer. The file pointer associated with stream (if there is one) is increased by the number of bytes actually read. If the given stream is opened in text mode, carriage return–linefeed pairs are replaced with single linefeed characters. The replacement has no effect on the file pointer or the return value. The file-pointer position is indeterminate if an error occurs. The value of a partially read item cannot be determined.

Example

/* FREAD.C: This program opens a file named FREAD.OUT and
 * writes 25 characters to the file. It then tries to open
 * FREAD.OUT and read in 25 characters. If the attempt succeeds,
 * the program displays the number of actual items read.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char list[30];
   int  i, numread, numwritten;

   /* Open file in text mode: */
   if( (stream = fopen( "fread.out", "w+t" )) != NULL )
   {
      for ( i = 0; i < 25; i++ )
         list[i] = (char)('z' - i);
      /* Write 25 characters to stream */
      numwritten = fwrite( list, sizeof( char ), 25, stream );
      printf( "Wrote %d items\n", numwritten );
      fclose( stream );

   }
   else
      printf( "Problem opening the file\n" );

   if( (stream = fopen( "fread.out", "r+t" )) != NULL )
   {
      /* Attempt to read in 25 characters */
      numread = fread( list, sizeof( char ), 25, stream );
      printf( "Number of items read = %d\n", numread );
      printf( "Contents of buffer = %.25s\n", list );
      fclose( stream );
   }
   else
      printf( "File could not be opened\n" );
}

Output

Wrote 25 items
Number of items read = 25
Contents of buffer = zyxwvutsrqponmlkjihgfedcb

Stream I/O Routines

See Also fwrite, _read


free

Deallocates or frees a memory block.

void free( void *memblock );

Function | Required Header | Compatibility
free | <stdlib.h> and <malloc.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

memblock

Previously allocated memory block to be freed

Remarks

The free function deallocates a memory block (memblock) that was previously allocated by a call to calloc, malloc, or realloc. The number of freed bytes is equivalent to the number of bytes requested when the block was allocated (or reallocated, in the case of realloc). If memblock is NULL, the pointer is ignored and free immediately returns. Attempting to free an invalid pointer (a pointer to a memory block that was not allocated by calloc, malloc, or realloc) may affect subsequent allocation requests and cause errors.

After a memory block has been freed, _heapmin minimizes the amount of free memory on the heap by coalescing the unused regions and releasing them back to the operating system. Freed memory that is not released to the operating system is restored to the free pool and is available for allocation again.

When the application is linked with a debug version of the C run-time libraries, free resolves to _free_dbg. For more information about how the heap is managed during the debugging process, see Using C Run-Time Library Debugging Support.

Example

/* MALLOC.C: This program allocates memory with
 * malloc, then frees the memory with free.
 */

#include <stdlib.h>         /* For _MAX_PATH definition */
#include <stdio.h>
#include <malloc.h>

void main( void )
{
   char *string;

   /* Allocate space for a path name */
   string = malloc( _MAX_PATH );
   if( string == NULL )
      printf( "Insufficient memory available\n" );
   else
   {
      printf( "Memory space allocated for path name\n" );
      free( string );
      printf( "Memory freed\n" );
   }
}

Output

Memory space allocated for path name
Memory freed

Memory Allocation Routines

See Also _alloca, calloc, malloc, realloc, _free_dbg, _heapmin


freopen, _wfreopen

Reassign a file pointer.

FILE *freopen( const char *path, const char *mode, FILE *stream );

FILE *_wfreopen( const wchar_t *path, const wchar_t *mode, FILE *stream );

Function | Required Header | Compatibility
freopen | <stdio.h> | ANSI, Win 95, Win NT
_wfreopen | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the newly opened file. If an error occurs, the original file is closed and the function returns a NULL pointer value.

Parameters

path

Path of new file

mode

Type of access permitted

stream

Pointer to FILE structure

Remarks

The freopen function closes the file currently associated with stream and reassigns stream to the file specified by path. _wfreopen is a wide-character version of _freopen; the path and mode arguments to _wfreopen are wide-character strings. _wfreopen and _freopen behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tfreopen | freopen | freopen | _wfreopen

freopen is typically used to redirect the pre-opened files stdin, stdout, and stderr to files specified by the user. The new file associated with stream is opened with mode, which is a character string specifying the type of access requested for the file, as follows:

"r"

Opens for reading. If the file does not exist or cannot be found, the freopen call fails.

"w"

Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"

Opens for writing at the end of the file (appending) without removing the EOF marker before writing new data to the file; creates the file first if it does not exist.

"r+"

Opens for both reading and writing. (The file must exist.)

"w+"

Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"

Opens for reading and appending; the appending operation includes the removal of the EOF marker before new data is written to the file and the EOF marker is restored after writing is complete; creates the file first if it does not exist.

Use the "w" and "w+" types with care, as they can destroy existing files.

When a file is opened with the "a" or "a+" access type, all write operations take place at the end of the file. Although the file pointer can be repositioned using fseek or rewind, the file pointer is always moved back to the end of the file before any write operation is carried out. Thus, existing data cannot be overwritten.

The "a" mode does not remove the EOF marker before appending to the file. After appending has occurred, the MS-DOS TYPE command only shows data up to the original EOF marker and not any data appended to the file. The "a+" mode does remove the EOF marker before appending to the file. After appending, the MS-DOS TYPE command shows all data in the file. The "a+" mode is required for appending to a stream file that is terminated with the CTRL+Z EOF marker.

When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for “update”). However, when you switch between reading and writing, there must be an intervening fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired. In addition to the above values, one of the following characters may be included in the mode string to specify the translation mode for new lines.

t

Open in text (translated) mode; carriage return–linefeed (CR-LF) combinations are translated into single linefeed (LF) characters on input; LF characters are translated to CR-LF combinations on output. Also, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading or for writing and reading with "a+", the run-time library checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using fseek and ftell to move within a file may cause fseek to behave improperly near the end of the file. The t option is a Microsoft extension that should not be used where ANSI portability is desired.

b

Open in binary (untranslated) mode; the above translations are suppressed.

If t or b is not given in the mode string, the translation mode is defined by the default mode variable _fmode.

For a discussion of text and binary modes, see Text and Binary Mode File I/O.

Example

/* FREOPEN.C: This program reassigns stderr to the file
 * named FREOPEN.OUT and writes a line to that file.
 */

#include <stdio.h>
#include <stdlib.h>

FILE *stream;

void main( void )
{
   /* Reassign "stderr" to "freopen.out": */
   stream = freopen( "freopen.out", "w", stderr );

   if( stream == NULL )
      fprintf( stdout, "error on freopen\n" );
   else
   {
      fprintf( stream, "This will go to the file 'freopen.out'\n" );
      fprintf( stdout, "successfully reassigned\n" );
      fclose( stream );
   }
   system( "type freopen.out" );
}

Output

successfully reassigned
This will go to the file 'freopen.out'

Stream I/O Routines

See Also fclose, _fdopen, _fileno, fopen, _open, _setmode


frexp

Gets the mantissa and exponent of a floating-point number.

double frexp( double x, int *expptr );

Function | Required Header | Compatibility
frexp | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

frexp returns the mantissa. If x is 0, the function returns 0 for both the mantissa and the exponent. There is no error return.

Parameters

x

Floating-point value

expptr

Pointer to stored integer exponent

Remarks

The frexp function breaks down the floating-point value (x) into a mantissa (m) and an exponent (n), such that the absolute value of m is greater than or equal to 0.5 and less than 1.0, and x = m*2n. The integer exponent n is stored at the location pointed to by expptr.

Example

/* FREXP.C: This program calculates frexp( 16.4, &n )
 * then displays y and n.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x, y;
   int n;

   x = 16.4;
   y = frexp( x, &n );
   printf( "frexp( %f, &n ) = %f, n = %d\n", x, y, n );
}

Output

frexp( 16.400000, &n ) = 0.512500, n = 5

Floating-Point Support Routines

See Also ldexp, modf


fscanf, fwscanf

Read formatted data from a stream.

int fscanf( FILE *stream, const char *format [, argument ]... );

int fwscanf( FILE *stream, const wchar_t *format [, argument ]... );

Function | Required Header | Compatibility
fscanf | <stdio.h> | ANSI, Win 95, Win NT
fwscanf | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the number of fields successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. If an error occurs, or if the end of the file stream is reached before the first conversion, the return value is EOF for fscanf or WEOF for fwscanf.

Parameters

stream

Pointer to FILE structure

format

Format-control string

argument

Optional arguments

Remarks

The fscanf function reads data from the current position of stream into the locations given by argument (if any). Each argument must be a pointer to a variable of a type that corresponds to a type specifier in format. format controls the interpretation of the input fields and has the same form and function as the format argument for scanf; see scanf for a description of format. If copying takes place between strings that overlap, the behavior is undefined.

fwscanf is a wide-character version of fscanf; the format argument to fwscanf is a wide-character string. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_ftscanf | fscanf | fscanf | fwscanf

For more information, see Format Specification Fields – scanf functions and wscanf Functions.

Example

/* FSCANF.C: This program writes formatted
 * data to a file. It then uses fscanf to
 * read the various data back from the file.
 */

#include <stdio.h>

FILE *stream;

void main( void )
{
   long l;
   float fp;
   char s[81];
   char c;

   stream = fopen( "fscanf.out", "w+" );
   if( stream == NULL )
      printf( "The file fscanf.out was not opened\n" );
   else
   {
      fprintf( stream, "%s %ld %f%c", "a-string",
               65000, 3.14159, 'x' );

      /* Set pointer to beginning of file: */
      fseek( stream, 0L, SEEK_SET );

      /* Read data back from file: */
      fscanf( stream, "%s", s );
      fscanf( stream, "%ld", &l );

      fscanf( stream, "%f", &fp );
      fscanf( stream, "%c", &c );

      /* Output data read: */
      printf( "%s\n", s );
      printf( "%ld\n", l );
      printf( "%f\n", fp );
      printf( "%c\n", c );

      fclose( stream );
   }
}

Output

a-string
65000
3.141590
x

Stream I/O Routines

See Also _cscanf, fprintf, scanf, sscanf


fseek

Moves the file pointer to a specified location.

int fseek( FILE *stream, long offset, int origin );

Function | Required Header | Compatibility
fseek | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, fseek returns 0. Otherwise, it returns a nonzero value. On devices incapable of seeking, the return value is undefined.

Parameters

stream

Pointer to FILE structure

offset

Number of bytes from origin

origin

Initial position

Remarks

The fseek function moves the file pointer (if any) associated with stream to a new location that is offset bytes from origin. The next operation on the stream takes place at the new location. On a stream open for update, the next operation can be either a read or a write. The argument origin must be one of the following constants, defined in STDIO.H:

SEEK_CUR

Current position of file pointer

SEEK_END

End of file

SEEK_SET

Beginning of file

You can use fseek to reposition the pointer anywhere in a file. The pointer can also be positioned beyond the end of the file. fseek clears the end-of-file indicator and negates the effect of any prior ungetc calls against stream.

When a file is opened for appending data, the current file position is determined by the last I/O operation, not by where the next write would occur. If no I/O operation has yet occurred on a file opened for appending, the file position is the start of the file.

For streams opened in text mode, fseek has limited use, because carriage return–linefeed translations can cause fseek to produce unexpected results. The only fseek operations guaranteed to work on streams opened in text mode are:

  • Seeking with an offset of 0 relative to any of the origin values.

  • Seeking from the beginning of the file with an offset value returned from a call to ftell.

Also in text mode, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing, fopen and all related routines check for a CTRL+Z at the end of the file and remove it if possible. This is done because using fseek and ftell to move within a file that ends with a CTRL+Z may cause fseek to behave improperly near the end of the file.

Example

/* FSEEK.C: This program opens the file FSEEK.OUT and
 * moves the pointer to the file's beginning.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char line[81];
   int  result;

   stream = fopen( "fseek.out", "w+" );
   if( stream == NULL )
      printf( "The file fseek.out was not opened\n" );
   else
   {
      fprintf( stream, "The fseek begins here: "
                       "This is the file 'fseek.out'.\n" );
      result = fseek( stream, 23L, SEEK_SET);
      if( result )
         perror( "Fseek failed" );
      else
      {
         printf( "File pointer is set to middle of first line.\n" );
         fgets( line, 80, stream );
         printf( "%s", line );

      }
      fclose( stream );
   }
}

Output

File pointer is set to middle of first line.
This is the file 'fseek.out'.

Stream I/O Routines

See Also ftell, _lseek, rewind


fsetpos

Sets the stream-position indicator.

int fsetpos( FILE *stream, const fpos_t *pos );

Function | Required Header | Compatibility
fsetpos | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, fsetpos returns 0. On failure, the function returns a nonzero value and sets errno to one of the following manifest constants (defined in ERRNO.H): EBADF, which means the file is not accessible or the object that stream points to is not a valid file handle; or EINVAL, which means an invalid stream value was passed.

Parameters

stream

Pointer to FILE structure

pos

Position-indicator storage

Remarks

The fsetpos function sets the file-position indicator for stream to the value of pos, which is obtained in a prior call to fgetpos against stream. The function clears the end-of-file indicator and undoes any effects of ungetc on stream. After calling fsetpos, the next operation on stream may be either input or output.

Example

/* FGETPOS.C: This program opens a file and reads
 * bytes at several different locations.
 */

#include <stdio.h>

void main( void )
{
   FILE   *stream;
   fpos_t pos;
   char   buffer[20];

   if( (stream = fopen( "fgetpos.c", "rb" )) == NULL )
      printf( "Trouble opening file\n" );
   else
   {
      /* Read some data and then check the position. */
      fread( buffer, sizeof( char ), 10, stream );
      if( fgetpos( stream, &pos ) != 0 )
         perror( "fgetpos error" );
      else
      {
         fread( buffer, sizeof( char ), 10, stream );
         printf( "10 bytes at byte %ld: %.10s\n", pos, buffer );
      }

   /* Set a new position and read more data */
   pos = 140;
   if( fsetpos( stream, &pos ) != 0 )
      perror( "fsetpos error" );

   fread( buffer, sizeof( char ), 10, stream );
   printf( "10 bytes at byte %ld: %.10s\n", pos, buffer );
   fclose( stream );
   }
}

Output

10 bytes at byte 10: .C: This p
10 bytes at byte 140:
{
   FIL

Stream I/O Routines

See Also fgetpos


_fsopen, _wfsopen

Open a stream with file sharing.

FILE *_fsopen( const char *filename, const char *mode, int shflag );

FILE *_wfsopen( const wchar_t *filename, const wchar_t *mode, int shflag );

Function | Required Header | Optional Headers | Compatibility
_fsopen | <stdio.h> | <share.h>1 | Win 95, Win NT
_wfsopen | <stdio.h> or <wchar.h> | <share.h>1 | Win NT

1 For manifest constant for shflag parameter.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the stream. A NULL pointer value indicates an error.

Parameters

filename

Name of file to open

mode

Type of access permitted

shflag

Type of sharing allowed

Remarks

The _fsopen function opens the file specified by filename as a stream and prepares the file for subsequent shared reading or writing, as defined by the mode and shflag arguments. _wfsopen is a wide-character version of _fsopen; the filename and mode arguments to _wfsopen are wide-character strings. _wfsopen and _fsopen behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tfsopen | _fsopen | _fsopen | _wfsopen

The character string mode specifies the type of access requested for the file, as follows:

"r"

Opens for reading. If the file does not exist or cannot be found, the _fsopen call fails.

"w"

Opens an empty file for writing. If the given file exists, its contents are destroyed.

"a"

Opens for writing at the end of the file (appending); creates the file first if it does not exist.

"r+"

Opens for both reading and writing. (The file must exist.)

"w+"

Opens an empty file for both reading and writing. If the given file exists, its contents are destroyed.

"a+"

Opens for reading and appending; creates the file first if it does not exist.

Use the "w" and "w+" types with care, as they can destroy existing files.

When a file is opened with the "a" or "a+" access type, all write operations occur at the end of the file. The file pointer can be repositioned using fseek or rewind, but is always moved back to the end of the file before any write operation is carried out. Thus existing data cannot be overwritten. When the "r+", "w+", or "a+" access type is specified, both reading and writing are allowed (the file is said to be open for “update”). However, when switching between reading and writing, there must be an intervening fsetpos, fseek, or rewind operation. The current position can be specified for the fsetpos or fseek operation, if desired. In addition to the above values, one of the following characters can be included in mode to specify the translation mode for new lines:

t

Opens a file in text (translated) mode. In this mode, carriage return–linefeed (CR-LF) combinations are translated into single linefeeds (LF) on input and LF characters are translated to CR-LF combinations on output. Also, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading or reading/writing, _fsopen checks for a CTRL+Z at the end of the file and removes it, if possible. This is done because using fseek and ftell to move within a file that ends with a CTRL+Z may cause fseek to behave improperly near the end of the file.

b

Opens a file in binary (untranslated) mode; the above translations are suppressed.

If t or b is not given in mode, the translation mode is defined by the default-mode variable _fmode. If t or b is prefixed to the argument, the function fails and returns NULL. For a discussion of text and binary modes, see Text and Binary Mode File I/O.

The argument shflag is a constant expression consisting of one of the following manifest constants, defined in SHARE.H:

_SH_COMPAT

Sets Compatibility mode for 16-bit applications

_SH_DENYNO

Permits read and write access

_SH_DENYRD

Denies read access to file

_SH_DENYRW

Denies read and write access to file

_SH_DENYWR

Denies write access to file

Example

/* FSOPEN.C:
 */

#include <stdio.h>
#include <stdlib.h>
#include <share.h>

void main( void )
{
   FILE *stream;

   /* Open output file for writing. Using _fsopen allows us to
    * ensure that no one else writes to the file while we are
    * writing to it.
    */
   if( (stream = _fsopen( "outfile", "wt", _SH_DENYWR )) != NULL )
   {
      fprintf( stream, "No one else in the network can write "
                       "to this file until we are done.\n" );
      fclose( stream );
   }
   /* Now others can write to the file while we read it. */
   system( "type outfile" );
}

Output

No one else in the network can write to this file until we are done.

Stream I/O Routines

See Also fclose, _fdopen, ferror, _fileno, fopen, freopen, _open, _setmode, _sopen


_fstat, _fstati64

Get information about an open file.

int _fstat( int handle, struct _stat *buffer );

__int64 _fstati64( int handle, struct _stat *buffer );

Function | Required Header | Compatibility
_fstat | <sys/stat.h> and <sys/types.h> | Win 95, Win NT
_fstati64 | <sys/stat.h> and <sys/types.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_fstat and _fstati64 return 0 if the file-status information is obtained. A return value of –1 indicates an error, in which case errno is set to EBADF, indicating an invalid file handle.

Parameters

handle

Handle of open file

buffer

Pointer to structure to store results

Remarks

The _fstat function obtains information about the open file associated with handle and stores it in the structure pointed to by buffer. The _stat structure, defined in SYS\STAT.H, contains the following fields:

st_atime

Time of last file access.

st_ctime

Time of creation of file.

st_dev

If a device, handle; otherwise 0.

st_mode

Bit mask for file-mode information. The _S_IFCHR bit is set if handle refers to a device. The _S_IFREG bit is set if handle refers to an ordinary file. The read/write bits are set according to the file’s permission mode. _S_IFCHR and other constants are defined in SYS\STAT.H.

st_mtime

Time of last modification of file.

st_nlink

Always 1 on non-NTFS file systems.

st_rdev

If a device, handle; otherwise 0.

st_size

Size of the file in bytes.

If handle refers to a device, the st_atime, st_ctime, and st_mtime and st_size fields are not meaningful.

Because STAT.H uses the _dev_t type, which is defined in TYPES.H, you must include TYPES.H before STAT.H in your code.

Example

/* FSTAT.C: This program uses _fstat to report
 * the size of a file named F_STAT.OUT.
 */

#include <io.h>
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void main( void )
{
   struct _stat buf;
   int fh, result;
   char buffer[] = "A line to output";

   if( (fh = _open( "f_stat.out", _O_CREAT | _O_WRONLY |
                                  _O_TRUNC )) ==  -1 )
   _write( fh, buffer, strlen( buffer ) );

   /* Get data associated with "fh": */
   result = _fstat( fh, &buf );

   /* Check if statistics are valid: */
   if( result != 0 )
      printf( "Bad file handle\n" );
   else
   {
      printf( "File size     : %ld\n", buf.st_size );

      printf( "Time modified : %s", ctime( &buf.st_ctime ) );
   }
   _close( fh );
}

Output

File size     : 0
Time modified : Tue Mar 21 15:23:08 1995

File Handling Routines

See Also _access, _chmod, _filelength, _stat


ftell

Gets the current position of a file pointer.

long ftell( FILE *stream );

Function | Required Header | Optional Headers | Compatibility
ftell | <stdio.h> | <errno.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

ftell returns the current file position. The value returned by ftell may not reflect the physical byte offset for streams opened in text mode, because text mode causes carriage return–linefeed translation. Use ftell with fseek to return to file locations correctly. On error, ftell returns –1L and errno is set to one of two constants, defined in ERRNO.H. The EBADF constant means the stream argument is not a valid file-handle value or does not refer to an open file. EINVAL means an invalid stream argument was passed to the function. On devices incapable of seeking (such as terminals and printers), or when stream does not refer to an open file, the return value is undefined.

Parameter

stream

Target FILE structure

Remarks

The ftell function gets the current position of the file pointer (if any) associated with stream. The position is expressed as an offset relative to the beginning of the stream.

Note that when a file is opened for appending data, the current file position is determined by the last I/O operation, not by where the next write would occur. For example, if a file is opened for an append and the last operation was a read, the file position is the point where the next read operation would start, not where the next write would start. (When a file is opened for appending, the file position is moved to end of file before any write operation.) If no I/O operation has yet occurred on a file opened for appending, the file position is the beginning of the file.

In text mode, CTRL+Z is interpreted as an end-of-file character on input. In files opened for reading/writing, fopen and all related routines check for a CTRL+Z at the end of the file and remove it if possible. This is done because using ftell and fseek to move within a file that ends with a CTRL+Z may cause ftell to behave improperly near the end of the file.

Example

/* FTELL.C: This program opens a file named FTELL.C
 * for reading and tries to read 100 characters. It
 * then uses ftell to determine the position of the
 * file pointer and displays this position.
 */

#include <stdio.h>

FILE *stream;

void main( void )
{
   long position;
   char list[100];
   if( (stream = fopen( "ftell.c", "rb" )) != NULL )
   {
      /* Move the pointer by reading data: */
      fread( list, sizeof( char ), 100, stream );
      /* Get position after read: */
      position = ftell( stream );
      printf( "Position after trying to read 100 bytes: %ld\n",
              position );
      fclose( stream );
   }
}

Output

Position after trying to read 100 bytes: 100

Stream I/O Routines

See Also fgetpos, fseek, _lseek, _tell


_ftime

Gets the current time.

void _ftime( struct _timeb *timeptr );

Function | Required Header | Compatibility
_ftime | <sys/types.h> and <sys/timeb.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ftime does not return a value, but fills in the fields of the structure pointed to by timeptr.

Parameter

timeptr

Pointer to _timeb structure

Remarks

The _ftime function gets the current local time and stores it in the structure pointed to by timeptr. The _timeb structure is defined in SYS\TIMEB.H. It contains four fields:

dstflag

Nonzero if daylight savings time is currently in effect for the local time zone. (See _tzset for an explanation of how daylight savings time is determined.)

millitm

Fraction of a second in milliseconds.

time

Time in seconds since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC).

timezone

Difference in minutes, moving westward, between UTC and local time. The value of timezone is set from the value of the global variable _timezone (see _tzset).

Example

/* FTIME.C: This program uses _ftime to obtain the current
 * time and then stores this time in timebuffer.
 */

#include <stdio.h>
#include <sys/timeb.h>
#include <time.h>

void main( void )
{
   struct _timeb timebuffer;
   char *timeline;

   _ftime( &timebuffer );
   timeline = ctime( & ( timebuffer.time ) );

   printf( "The time is %.19s.%hu %s", timeline, timebuffer.millitm, &timeline[20] );
}

Output

The time is Tue Mar 21 15:26:41.341 1995

Time Management Routines

See Also asctime, ctime, gmtime, localtime, time


_fullpath, _wfullpath

Create an absolute or full path name for the specified relative path name.

char *_fullpath( char *absPath, const char *relPath, size_t maxLength );

wchar_t *_wfullpath( wchar_t *absPath, const wchar_t *relPath, size_t maxLength );

Function | Required Header | Compatibility
_fullpath | <stdlib.h> | Win 95, Win NT
_wfullpath | <stdlib.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to a buffer containing the absolute path name (absPath). If there is an error (for example, if the value passed in relPath includes a drive letter that is not valid or cannot be found, or if the length of the created absolute path name (absPath) is greater than maxLength) the function returns NULL.

Parameters

absPath

Pointer to a buffer containing the absolute or full path name

relPath

Relative path name

maxLength

Maximum length of the absolute path name buffer (absPath). This length is in bytes for _fullpath but in wide characters (wchar_t) for _wfullpath.

Remarks

The _fullpath function expands the relative path name in relPath to its fully qualified or “absolute” path, and stores this name in absPath. A relative path name specifies a path to another location from the current location (such as the current working directory: “.”). An absolute path name is the expansion of a relative path name that states the entire path required to reach the desired location from the root of the filesystem. Unlike _makepath, _fullpath can be used to obtain the absolute path name for relative paths (relPath) that include “./” or “../” in their names.

For example, to use C run-time routines, the application must include the header files that contain the declarations for the routines. Each header file include statement references the location of the file in a relative manner (from the application’s working directory):

#include <stdlib.h>

when the absolute path (actual file system location) of the file may be:

\\machine\shareName\msvcSrc\crt\headerFiles\stdlib.h

_fullpath automatically handles multibyte-character string arguments as appropriate, recognizing multibyte-character sequences according to the multibyte code page currently in use. _wfullpath is a wide-character version of _fullpath; the string arguments to _wfullpath are wide-character strings. _wfullpath and _fullpath behave identically except that _wfullpath does not handle multibyte-character strings.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tfullpath | _fullpath | _fullpath | _wfullpath

If the absPath buffer is NULL, _fullpath calls malloc to allocate a buffer of size _MAX_PATH and ignores the maxLength argument. It is the caller’s responsibility to deallocate this buffer (using free) as appropriate. If the relPath argument specifies a disk drive, the current directory of this drive is combined with the path.

Example

/* FULLPATH.C: This program demonstrates how _fullpath
 * creates a full path from a partial path.
 */

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <direct.h>

char full[_MAX_PATH], part[_MAX_PATH];

void main( void )
{
   while( 1 )
   {
      printf( "Enter partial path or ENTER to quit: " );
      gets( part );
      if( part[0] == 0 )
         break;

      if( _fullpath( full, part, _MAX_PATH ) != NULL )
         printf( "Full path is: %s\n", full );
      else
         printf( "Invalid path\n" );
   }
}

File Handling Routines

See Also _getcwd, _getdcwd, _makepath, _splitpath


_futime

Sets modification time on an open file.

int _futime( int handle, struct _utimbuf *filetime );

Function | Required Header | Optional Headers | Compatibility
_futime | <sys/utime.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_futime returns 0 if successful. If an error occurs, this function returns –1 and errno is set to EBADF, indicating an invalid file handle.

Parameters

handle

Handle to open file

filetime

Pointer to structure containing new modification date

Remarks

The _futime routine sets the modification date and the access time on the open file associated with handle. _futime is identical to _utime, except that its argument is the handle to an open file, rather than the name of a file or a path to a file. The _utimbuf structure contains fields for the new modification date and access time. Both fields must contain valid values.

Example

/* FUTIME.C: This program uses _futime to set the
 * file-modification time to the current time.
 */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/utime.h>

void main( void )
{

   int hFile;

   /* Show file time before and after. */
   system( "dir futime.c" );

   hFile = _open("futime.c", _O_RDWR);

   if( _futime( hFile, NULL ) == -1 )
      perror( "_futime failed\n" );
   else
      printf( "File time modified\n" );

   close (hFile);

   system( "dir futime.c" );

}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 1D37-7A7A

 Directory of C:\code

05/03/95  01:30p                   601 futime.c
               1 File(s)            601 bytes
                             16,269,312 bytes free
 Volume in drive C is CDRIVE
 Volume Serial Number is 1D37-7A7A

 Directory of C:\code

05/03/95  01:36p                   601 futime.c
               1 File(s)            601 bytes
                             16,269,312 bytes free
File time modified

Time Management Routines


fwrite

Writes data to a stream.

size_t fwrite( const void *buffer, size_t size, size_t count, FILE *stream );

Function | Required Header | Compatibility
fwrite | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

fwrite returns the number of full items actually written, which may be less than count if an error occurs. Also, if an error occurs, the file-position indicator cannot be determined.

Parameters

buffer

Pointer to data to be written

size

Item size in bytes

count

Maximum number of items to be written

stream

Pointer to FILE structure

Remarks

The fwrite function writes up to count items, of size length each, from buffer to the output stream. The file pointer associated with stream (if there is one) is incremented by the number of bytes actually written. If stream is opened in text mode, each carriage return is replaced with a carriage-return – linefeed pair. The replacement has no effect on the return value.

Example

/* FREAD.C: This program opens a file named FREAD.OUT and
 * writes 25 characters to the file. It then tries to open
 * FREAD.OUT and read in 25 characters. If the attempt succeeds,
 * the program displays the number of actual items read.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char list[30];
   int  i, numread, numwritten;

   /* Open file in text mode: */
   if( (stream = fopen( "fread.out", "w+t" )) != NULL )
   {
      for ( i = 0; i < 25; i++ )
         list[i] = (char)('z' - i);
      /* Write 25 characters to stream */
      numwritten = fwrite( list, sizeof( char ), 25, stream );
      printf( "Wrote %d items\n", numwritten );
      fclose( stream );

   }
   else
      printf( "Problem opening the file\n" );

   if( (stream = fopen( "fread.out", "r+t" )) != NULL )
   {
      /* Attempt to read in 25 characters */
      numread = fread( list, sizeof( char ), 25, stream );
      printf( "Number of items read = %d\n", numread );
      printf( "Contents of buffer = %.25s\n", list );
      fclose( stream );
   }
   else
      printf( "File could not be opened\n" );
}

Output

Wrote 25 items
Number of items read = 25
Contents of buffer = zyxwvutsrqponmlkjihgfedcb

Stream I/O Routines

See Also fread, _write


_gcvt

Converts a floating-point value to a string, which it stores in a buffer.

char *_gcvt( double value, int digits, char *buffer );

Routine | Required Header | Compatibility
_gcvt | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_gcvt returns a pointer to the string of digits. There is no error return.

Parameters

value

Value to be converted

digits

Number of significant digits stored

buffer

Storage location for result

Remarks

The _gcvt function converts a floating-point value to a character string (which includes a decimal point and a possible sign byte) and stores the string in buffer. The buffer should be large enough to accommodate the converted value plus a terminating null character, which is appended automatically. If a buffer size of digits + 1 is used, the function overwrites the end of the buffer. This is because the converted string includes a decimal point and can contain sign and exponent information. There is no provision for overflow. _gcvt attempts to produce digits digits in decimal format. If it cannot, it produces digits digits in exponential format. Trailing zeros may be suppressed in the conversion.

Example

/* _GCVT.C: This program converts -3.1415e5
 * to its string representation.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[50];
   double source = -3.1415e5;
   _gcvt( source, 7, buffer );
   printf( "source: %f  buffer: '%s'\n", source, buffer );
   _gcvt( source, 7, buffer );
   printf( "source: %e  buffer: '%s'\n", source, buffer );
}

Output

source: -314150.000000  buffer: '-314150.'
source: -3.141500e+005  buffer: '-314150.'

Data Conversion Routines | Floating-Point Support Routines

See Also atof, _ecvt, _fcvt


getc, getwc, getchar, getwchar

Read a character from a stream (getc, getwc), or get a character from stdin (getchar, getwchar).

int getc( FILE *stream );

wint_t getwc( FILE *stream );

int getchar( void );

wint_t getwchar( void );

Routine | Required Header | Compatibility
getc | <stdio.h> | ANSI, Win 95, Win NT
getwc | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT
getchar | <stdio.h> | ANSI, Win 95, Win NT
getwchar | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the character read. To indicate an read error or end-of-file condition, getc and getchar return EOF, and getwc and getwchar return WEOF. For getc and getchar, use ferror or feof to check for an error or for end of file.

Parameter

stream

Input stream

Remarks

Each of these routines reads a single character from a file at the current position and increments the associated file pointer (if defined) to point to the next character. In the case of getc and getwc, the file is associated with stream (see Choosing Between Functions and Macros). Routine-specific remarks follow.

Routine | Remarks
getc | Same as fgetc, but implemented as a function and as a macro.
getwc | Wide-character version of getc. Reads a multibyte character or a wide character according to whether stream is opened in text mode or binary mode.
getchar | Same as _fgetchar, but implemented as a function and as a macro.
getwchar | Wide-character version of getchar. Reads a multibyte character or a wide character according to whether stream is opened in text mode or binary mode.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_gettc | getc | getc | getwc
_gettchar | getchar | getchar | getwchar

Example

/* GETC.C: This program uses getchar to read a single line
 * of input from stdin, places this input in buffer, then
 * terminates the string before printing it to the screen.
 */

#include <stdio.h>

void main( void )
{
   char buffer[81];
   int i, ch;

   printf( "Enter a line: " );

   /* Read in single line from "stdin": */
   for( i = 0; (i < 80) &&  ((ch = getchar()) != EOF)
                        && (ch != '\n'); i++ )
      buffer[i] = (char)ch;

   /* Terminate string with null character: */
   buffer[i] = '\0';
   printf( "%s\n", buffer );
}

Output

Enter a line: This is a test
This is a test

Stream I/O Routines

See Also fgetc, _getch, putc, ungetc


_getch, _getche

Get a character from the console without echo (_getch) or with echo (_getche).

int _getch( void );

int _getche( void );

Routine | Required Header | Compatibility
_getch | <conio.h> | Win 95, Win NT
_getche | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Both _getch and _getche return the character read. There is no error return.

Remarks

The _getch function reads a single character from the console without echoing. _getche reads a single character from the console and echoes the character read. Neither function can be used to read CTRL+C. When reading a function key or an arrow key, _getch and _getche must be called twice; the first call returns 0 or 0xE0, and the second call returns the actual key code.

Example

/* GETCH.C: This program reads characters from
 * the keyboard until it receives a 'Y' or 'y'.
 */

#include <conio.h>
#include <ctype.h>

void main( void )
{
   int ch;

   _cputs( "Type 'Y' when finished typing keys: " );
   do
   {
      ch = _getch();
      ch = toupper( ch );
   } while( ch != 'Y' );

   _putch( ch );
   _putch( '\r' );    /* Carriage return */
   _putch( '\n' );    /* Line feed       */
}

Output

Type 'Y' when finished typing keys: Y

Console and Port I/O Routines

See Also _cgets, getc, _ungetch


_getcwd, _wgetcwd

Get the current working directory.

char *_getcwd( char *buffer, int maxlen );

wchar_t *_wgetcwd( wchar_t *buffer, int maxlen );

Routine | Required Header | Compatibility
_getcwd | <direct.h> | Win 95, Win NT
_wgetcwd | <direct.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to buffer. A NULL return value indicates an error, and errno is set either to ENOMEM, indicating that there is insufficient memory to allocate maxlen bytes (when a NULL argument is given as buffer), or to ERANGE, indicating that the path is longer than maxlen characters.

Parameters

buffer

Storage location for path

maxlen

Maximum length of path in characters: char for _getcwd and wchar_t for _wgetcwd

Remarks

The _getcwd function gets the full path of the current working directory for the default drive and stores it at buffer. The integer argument maxlen specifies the maximum length for the path. An error occurs if the length of the path (including the terminating null character) exceeds maxlen. The buffer argument can be NULL; a buffer of at least size maxlen (more only if necessary) will automatically be allocated, using malloc, to store the path. This buffer can later be freed by calling free and passing it the _getcwd return value (a pointer to the allocated buffer).

_getcwd returns a string that represents the path of the current working directory. If the current working directory is the root, the string ends with a backslash ( \ ). If the current working directory is a directory other than the root, the string ends with the directory name and not with a backslash.

_wgetcwd is a wide-character version of _getcwd; the buffer argument and return value of _wgetcwd are wide-character strings. _wgetcwd and _getcwd behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tgetcwd | _getcwd | _getcwd | _wgetcwd

Example

// GETCWD.C
/* This program places the name of the current directory in the
 * buffer array, then displays the name of the current directory
 * on the screen. Specifying a length of _MAX_PATH leaves room
 * for the longest legal path name.
 */

#include <direct.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[_MAX_PATH];

   /* Get the current working directory: */
   if( _getcwd( buffer, _MAX_PATH ) == NULL )
      perror( "_getcwd error" );
   else
      printf( "%s\n", buffer );
}

Output

C:\code

Directory Control Routines

See Also _chdir, _mkdir, _rmdir


_getdcwd, _wgetdcwd

Get full path name of current working directory on the specified drive.

char *_getdcwd( int drive, char *buffer, int maxlen );

wchar_t *_wgetdcwd( int drive, wchar_t *buffer, int maxlen );

Routine | Required Header | Compatibility
_getdcwd | <direct.h> | Win 95, Win NT
_wgetdcwd | <direct.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns buffer. A NULL return value indicates an error, and errno is set either to ENOMEM, indicating that there is insufficient memory to allocate maxlen bytes (when a NULL argument is given as buffer), or to ERANGE, indicating that the path is longer than maxlen characters.

Parameters

drive

Disk drive

buffer

Storage location for path

maxlen

Maximum length of path

Remarks

The _getdcwd function gets the full path of the current working directory on the specified drive and stores it at buffer. An error occurs if the length of the path (including the terminating null character) exceeds maxlen. The drive argument specifies the drive (0 = default drive, 1 = A, 2 = B, and so on). The buffer argument can be NULL; a buffer of at least size maxlen (more only if necessary) will automatically be allocated, using malloc, to store the path. This buffer can later be freed by calling free and passing it the _getdcwd return value (a pointer to the allocated buffer).

_getdcwd returns a string that represents the path of the current working directory. If the current working directory is set to the root, the string ends with a backslash ( \ ). If the current working directory is set to a directory other than the root, the string ends with the name of the directory and not with a backslash.

_wgetdcwd is a wide-character version of _getdcwd; the buffer argument and return value of _wgetdcwd are wide-character strings. _wgetdcwd and _getdcwd behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tgetdcwd | _getdcwd | _getdcwd | _wgetdcwd

Example

/* GETDRIVE.C illustrates drive functions including:
 *      _getdrive       _chdrive        _getdcwd
 */

#include <stdio.h>
#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>

void main( void )
{
   int ch, drive, curdrive;
   static char path[_MAX_PATH];

   /* Save current drive. */
   curdrive = _getdrive();

   printf( "Available drives are: \n" );

   /* If we can switch to the drive, it exists. */
   for( drive = 1; drive <= 26; drive++ )
      if( !_chdrive( drive ) )
         printf( "%c: ", drive + 'A' - 1 );

   while( 1 )
   {
      printf( "\nType drive letter to check or ESC to quit: " );
      ch = _getch();
      if( ch == 27 )
         break;
      if( isalpha( ch ) )
         _putch( ch );
      if( _getdcwd( toupper( ch ) - 'A' + 1, path, _MAX_PATH ) != NULL )
         printf( "\nCurrent directory on that drive is %s\n", path );
   }

   /* Restore original drive.*/
   _chdrive( curdrive );
   printf( "\n" );
}

Output

Available drives are:
A: B: C: L: M: O: U: V:
Type drive letter to check or ESC to quit: c
Current directory on that drive is C:\CODE

Type drive letter to check or ESC to quit: m
Current directory on that drive is M:\

Type drive letter to check or ESC to quit:

Directory Control Routines

See Also _chdir, _getcwd, _getdrive, _mkdir, _rmdir


_getdrive

Gets the current disk drive.

int _getdrive( void );

Routine | Required Header | Compatibility
_getdrive | <direct.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_getdrive returns the current (default) drive (1=A, 2=B, and so on). There is no error return.

Example

/* GETDRIVE.C illustrates drive functions including:
 *      _getdrive       _chdrive        _getdcwd
 */

#include <stdio.h>
#include <conio.h>
#include <direct.h>
#include <stdlib.h>
#include <ctype.h>

void main( void )
{
   int ch, drive, curdrive;
   static char path[_MAX_PATH];

   /* Save current drive. */
   curdrive = _getdrive();

   printf( "Available drives are: \n" );

   /* If we can switch to the drive, it exists. */
   for( drive = 1; drive <= 26; drive++ )
      if( !_chdrive( drive ) )
         printf( "%c: ", drive + 'A' - 1 );

   while( 1 )
   {
      printf( "\nType drive letter to check or ESC to quit: " );
      ch = _getch();
      if( ch == 27 )
         break;
      if( isalpha( ch ) )
         _putch( ch );
      if( _getdcwd( toupper( ch ) - 'A' + 1, path, _MAX_PATH ) != NULL )
         printf( "\nCurrent directory on that drive is %s\n", path );
   }

   /* Restore original drive.*/
   _chdrive( curdrive );
   printf( "\n" );
}

Output

Available drives are:
A: B: C: L: M: O: U: V:
Type drive letter to check or ESC to quit: c
Current directory on that drive is C:\CODE

Type drive letter to check or ESC to quit: m
Current directory on that drive is M:\

Type drive letter to check or ESC to quit:

Directory Control Routines

See Also _chdrive, _getcwd, _getdcwd


getenv, _wgetenv

Get a value from the current environment.

char *getenv( const char *varname );

wchar_t *_wgetenv( const wchar_t *varname );

Routine | Required Header | Compatibility
getenv | <stdlib.h> | ANSI, Win 95, Win NT
_wgetenv | <stdlib.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the environment table entry containing varname. It is not safe to modify the value of the environment variable using the returned pointer. Use the _putenv function to modify the value of an environment variable. The return value is NULL if varname is not found in the environment table.

Parameter

varname

Environment variable name

Remarks

The getenv function searches the list of environment variables for varname. getenv is not case sensitive in Windows NT and Windows 95. getenv and _putenv use the copy of the environment pointed to by the global variable _environ to access the environment. getenv operates only on the data structures accessible to the run-time library and not on the environment “segment” created for the process by the operating system. Therefore, programs that use the envp argument to main or wmain may retrieve invalid information.

_wgetenv is a wide-character version of getenv; the argument and return value of _wgetenv are wide-character strings. The _wenviron global variable is a wide-character version of _environ.

In an MBCS program (for example, in an SBCS ASCII program), _wenviron is initially NULL because the environment is composed of multibyte-character strings. Then, on the first call to _wputenv, or on the first call to _wgetenv if an (MBCS) environment already exists, a corresponding wide-character string environment is created and is then pointed to by _wenviron.

Similarly in a Unicode (_wmain) program, _environ is initially NULL because the environment is composed of wide-character strings. Then, on the first call to _putenv, or on the first call to getenv if a (Unicode) environment already exists, a corresponding MBCS environment is created and is then pointed to by _environ.

When two copies of the environment (MBCS and Unicode) exist simultaneously in a program, the run-time system must maintain both copies, resulting in slower execution time. For example, whenever you call _putenv, a call to _wputenv is also executed automatically, so that the two environment strings correspond.

Caution In rare instances, when the run-time system is maintaining both a Unicode version and a multibyte version of the environment, these two environment versions may not correspond exactly. This is because, although any unique multibyte-character string maps to a unique Unicode string, the mapping from a unique Unicode string to a multibyte-character string is not necessarily unique. For more information, see _environ, _wenviron.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tgetenv | getenv | getenv | _wgetenv

To check or change the value of the TZ environment variable, use getenv, _putenv and _tzset as necessary. For more information about TZ, see _tzset and see _daylight, timezone, and _tzname.

Example

/* GETENV.C: This program uses getenv to retrieve
 * the LIB environment variable and then uses
 * _putenv to change it to a new value.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char *libvar;

   /* Get the value of the LIB environment variable. */
   libvar = getenv( "LIB" );

   if( libvar != NULL )
      printf( "Original LIB variable is: %s\n", libvar );

   /* Attempt to change path. Note that this only affects the environment
    * variable of the current process. The command processor's environment
    * is not changed.
    */
   _putenv( "LIB=c:\\mylib;c:\\yourlib" );

   /* Get new value. */
   libvar = getenv( "LIB" );

   if( libvar != NULL )
      printf( "New LIB variable is: %s\n", libvar );
}

Output

Original LIB variable is: C:\progra~1\devstu~1\vc\lib
New LIB variable is: c:\mylib;c:\yourlib

Process and Environment Control Routines

See Also _putenv


_getmbcp

int _getmbcp( void );

Routine | Required Header | Compatibility
_getmbcp | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_getmbcp returns the current multibyte code page. A return value of 0 indicates that a single byte code page is in use.

See Also _setmbcp


_get_osfhandle

Gets operating-system file handle associated with existing stream FILE pointer.

long _get_osfhandle( int filehandle );

Routine | Required Header | Compatibility
_get_osfhandle | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _get_osfhandle returns an operating-system file handle corresponding to filehandle. Otherwise, it returns –1 and sets errno to EBADF, indicating an invalid file handle.

Parameter

filehandle

User file handle

Remarks

The _get_osfhandle function returns filehandle if it is in range and if it is internally marked as free.

File Handling Routines

See Also _close, _creat, _dup, _open


_getpid

Gets the process identification.

int _getpid( void );

Routine | Required Header | Compatibility
_getpid | <process.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_getpid returns the process ID obtained from the system. There is no error return.

Remarks

The _getpid function obtains the process ID from the system. The process ID uniquely identifies the calling process.

Example

/* GETPID.C: This program uses _getpid to obtain
 * the process ID and then prints the ID.
 */

#include <stdio.h>
#include <process.h>

void main( void )
{
   /* If run from command line, shows different ID for
    * command line than for operating system shell.
    */
   printf( "\nProcess id: %d\n", _getpid() );
}

Output

Process id: 193

Process and Environment Control Routines

See Also _mktemp


_get_sbh_threshold

Returns the upper limit for the size of a memory allocation that will be supported by the small-block heap.

size_t _get_sbh_threshold( void );

Routine | Required Header | Compatibility
_get_sbh_threshold | <malloc.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

This function returns the upper limit for the size of a memory allocation that will be supported by the small-block heap.

Remarks

Call this function to get the current threshold value for the small-block heap. The default threshold size is 480 bytes for Windows 95 and all Windows NT platforms except the DEC Alpha platforms, and 896 bytes for DEC Alpha Platforms.

Memory Allocation Routines

See Also _set_sbh_threshold


gets, _getws

Get a line from the stdin stream.

char *gets( char *buffer );

wchar_t *_getws( wchar_t *buffer );

Routine | Required Header | Compatibility
gets | <stdio.h> | ANSI, Win 95, Win NT
_getws | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns its argument if successful. A NULL pointer indicates an error or end-of-file condition. Use ferror or feof to determine which one has occurred.

Parameter

buffer

Storage location for input string

Remarks

The gets function reads a line from the standard input stream stdin and stores it in buffer. The line consists of all characters up to and including the first newline character ('\n'). gets then replaces the newline character with a null character ('\0') before returning the line. In contrast, the fgets function retains the newline character. _getws is a wide-character version of gets; its argument and return value are wide-character strings.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_getts | gets | gets | _getws

Example

/* GETS.C */

#include <stdio.h>

void main( void )
{
   char line[81];

   printf( "Input a string: " );
   gets( line );
   printf( "The line entered was: %s\n", line );
}

Output

Input a string: Hello!
The line entered was: Hello!

Stream I/O Routines

See Also fgets, fputs, puts


_getw

Gets an integer from a stream.

int _getw( FILE *stream );

Routine | Required Header | Compatibility
_getw | <stdio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_getw returns the integer value read. A return value of EOF indicates either an error or end of file. However, because the EOF value is also a legitimate integer value, use feof or ferror to verify an end-of-file or error condition.

Parameter

stream

Pointer to FILE structure

Remarks

The _getw function reads the next binary value of type int from the file associated with stream and increments the associated file pointer (if there is one) to point to the next unread character. _getw does not assume any special alignment of items in the stream. Problems with porting may occur with _getw because the size of the int type and the ordering of bytes within the int type differ across systems.

Example

/* GETW.C: This program uses _getw to read a word
 * from a stream, then performs an error check.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   FILE *stream;
   int i;

   if( (stream = fopen( "getw.c", "rb" )) == NULL )
      printf( "Couldn't open file\n" );
   else
   {
      /* Read a word from the stream: */
      i = _getw( stream );

      /* If there is an error... */
      if( ferror( stream ) )
      {
         printf( "_getw failed\n" );
         clearerr( stream );
      }
      else
         printf( "First data word in file: 0x%.4x\n", i );
      fclose( stream );
   }
}

Output

First data word in file: 0x47202a2f

Stream I/O Routines

See Also _putw


gmtime

Converts a time value to a structure.

struct tm *gmtime( const time_t *timer );

Routine | Required Header | Compatibility
gmtime | <time.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

gmtime returns a pointer to a structure of type tm. The fields of the returned structure hold the evaluated value of the timer argument in UTC rather than in local time. Each of the structure fields is of type int, as follows:

tm_sec

Seconds after minute (0 – 59)

tm_min

Minutes after hour (0 – 59)

tm_hour

Hours since midnight (0 – 23)

tm_mday

Day of month (1 – 31)

tm_mon

Month (0 – 11; January = 0)

tm_year

Year (current year minus 1900)

tm_wday

Day of week (0 – 6; Sunday = 0)

tm_yday

Day of year (0 – 365; January 1 = 0)

tm_isdst

Always 0 for gmtime

The gmtime, mktime, and localtime functions use the same single, statically allocated structure to hold their results. Each call to one of these functions destroys the result of any previous call. If timer represents a date before midnight, January 1, 1970, gmtime returns NULL. There is no error return.

Parameter

timer

Pointer to stored time. The time is represented as seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC).

Remarks

The gmtime function breaks down the timer value and stores it in a statically allocated structure of type tm, defined in TIME.H. The value of timer is usually obtained from a call to the time function.

Note The target environment should try to determine whether daylight savings time is in effect. The C run-time library assumes the United States’s rules for implementing the calculation of Daylight Saving Time (DST).

Example

/* GMTIME.C: This program uses gmtime to convert a long-
 * integer representation of coordinated universal time
 * to a structure named newtime, then uses asctime to
 * convert this structure to an output string.
 */

#include <time.h>
#include <stdio.h>

void main( void )
{
   struct tm *newtime;
   long ltime;

   time( &ltime );

   /* Obtain coordinated universal time: */
   newtime = gmtime( &ltime );
   printf( "Coordinated universal time is %s\n",
                               asctime( newtime ) );
}

Output

Coordinated universal time is Tue Mar 23 02:00:56 1993

Time Management Routines

See Also asctime, ctime, _ftime, localtime, mktime, time


_heapadd

Adds memory to the heap.

int _heapadd( void *memblock, size_t size );

Routine | Required Header | Optional Headers | Compatibility
_heapadd | <malloc.h> | <errno.h> | None

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _heapadd returns 0; otherwise, the function returns –1 and sets errno to ENOSYS.

Parameters

memblock

Pointer to heap memory

size

Size in bytes of memory to add

Remarks

Beginning with Visual C++ Version 4.0, the underlying heap structure was moved to the C run-time libraries to support the new debugging features. As a result, _heapadd is no longer supported on any Win32 platform and will immediately return –1 when called from an application of this type.

Memory Allocation Routines

See Also free, _heapchk, _heapmin, _heapset, _heapwalk, malloc, realloc


_heapchk

Runs consistency checks on the heap.

int _heapchk( void );

Routine | Required Header | Optional Headers | Compatibility
_heapchk | <malloc.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_heapchk returns one of the following integer manifest constants defined in MALLOC.H:

_HEAPBADBEGIN

Initial header information is bad or cannot be found

_HEAPBADNODE

Bad node has been found or heap is damaged

_HEAPBADPTR

Pointer into heap is not valid

_HEAPEMPTY

Heap has not been initialized

_HEAPOK

Heap appears to be consistent

In addition, if an error occurs, _heapchk sets errno to ENOSYS.

Remarks

The _heapchk function helps debug heap-related problems by checking for minimal consistency of the heap.

Example

/* HEAPCHK.C: This program checks the heap for
 * consistency and prints an appropriate message.
 */

#include <malloc.h>
#include <stdio.h>

void main( void )
{
   int  heapstatus;
   char *buffer;

   /* Allocate and deallocate some memory */
   if( (buffer = (char *)malloc( 100 )) != NULL )
      free( buffer );

   /* Check heap status */
   heapstatus = _heapchk();
   switch( heapstatus )
   {
   case _HEAPOK:
      printf(" OK - heap is fine\n" );
      break;
   case _HEAPEMPTY:
      printf(" OK - heap is empty\n" );
      break;
   case _HEAPBADBEGIN:
      printf( "ERROR - bad start of heap\n" );
      break;
   case _HEAPBADNODE:
      printf( "ERROR - bad node in heap\n" );
      break;
   }
}

Output

OK - heap is fine

Memory Allocation Routines

See Also _heapadd, _heapmin, _heapset, _heapwalk


_heapmin

Releases unused heap memory to the operating system.

int _heapmin( void );

Routine | Required Header | Optional Headers | Compatibility
_heapmin | <malloc.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _heapmin returns 0; otherwise, the function returns –1 and sets errno to ENOSYS.

Remarks

The _heapmin function minimizes the heap by releasing unused heap memory to the operating system.

Note In Visual C++ Version 4.0, the underlying heap structure was moved to the C run-time libraries to support the new debugging features. As a result, the only Win32 platform that is supported by _heapmin is Windows NT. The function returns –1 and sets errno to ENOSYS, when it is called by any other Win32 platform.

Memory Allocation Routines

See Also free, _heapadd, _heapchk, _heapset, _heapwalk, malloc


_heapset

Checks heaps for minimal consistency and sets the free entries to a specified value.

int _heapset( unsigned int fill );

Routine | Required Header | Optional Headers | Compatibility
_heapset | <malloc.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_heapset returns one of the following integer manifest constants defined in MALLOC.H:

_HEAPBADBEGIN

Initial header information invalid or not found

_HEAPBADNODE

Heap damaged or bad node found

_HEAPEMPTY

Heap not initialized

_HEAPOK

Heap appears to be consistent

In addition, if an error occurs, _heapset sets errno to ENOSYS.

Parameter

fill

Fill character

Remarks

The _heapset function shows free memory locations or nodes that have been unintentionally overwritten.

_heapset checks for minimal consistency on the heap, then sets each byte of the heap’s free entries to the fill value. This known value shows which memory locations of the heap contain free nodes and which contain data that were unintentionally written to freed memory.

Note In Visual C++ Version 4.0, the underlying heap structure was moved to the C run-time libraries to support the new debugging features. As a result, the only Win32 platform that is supported by _heapset is Windows NT. The function returns _HEAPOK and sets errno to ENOSYS, when it is called by any other Win32 platform.

Example

/* HEAPSET.C: This program checks the heap and
 * fills in free entries with the character 'Z'.
 */

#include <malloc.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int heapstatus;
   char *buffer;

   if( (buffer = malloc( 1 )) == NULL ) /* Make sure heap is */
      exit( 0 );                        /*    initialized    */
   heapstatus = _heapset( 'Z' );        /* Fill in free entries */
   switch( heapstatus )
   {
   case _HEAPOK:
      printf( "OK - heap is fine\n" );
      break;
   case _HEAPEMPTY:
      printf( "OK - heap is empty\n" );
      break;
   case _HEAPBADBEGIN:
      printf( "ERROR - bad start of heap\n" );
      break;
   case _HEAPBADNODE:
      printf( "ERROR - bad node in heap\n" );
      break;
   }
   free( buffer );
}

Output

OK - heap is fine

Memory Allocation Routines

See Also _heapadd, _heapchk, _heapmin, _heapwalk


_heapwalk

Traverses the heap and returns information about the next entry.

int _heapwalk( _HEAPINFO *entryinfo );

Routine | Required Header | Optional Headers | Compatibility
_heapwalk | <malloc.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_heapwalk returns one of the following integer manifest constants defined in MALLOC.H:

_HEAPBADBEGIN

Initial header information invalid or not found

_HEAPBADNODE

Heap damaged or bad node found

_HEAPBADPTR

_pentry field of _HEAPINFO structure does not contain valid pointer into heap

_HEAPEND

End of heap reached successfully

_HEAPEMPTY

Heap not initialized

_HEAPOK

No errors so far; _HEAPINFO structure contains information about next entry.

In addition, if an error occurs, _heapwalk sets errno to ENOSYS.

Parameter

entryinfo

Buffer to contain heap information

Remarks

The _heapwalk function helps debug heap-related problems in programs. The function walks through the heap, traversing one entry per call, and returns a pointer to a structure of type _HEAPINFO that contains information about the next heap entry. The _HEAPINFO type, defined in MALLOC.H, contains the following elements:

int *_pentry

Heap entry pointer

size_t _size

Size of heap entry

int _useflag

Flag that indicates whether heap entry is in use

A call to _heapwalk that returns _HEAPOK stores the size of the entry in the _size field and sets the _useflag field to either _FREEENTRY or _USEDENTRY (both are constants defined in MALLOC.H). To obtain this information about the first entry in the heap, pass _heapwalk a pointer to a _HEAPINFO structure whose _pentry member is NULL.

Note Beginning with Visual C++ Version 4.0, the underlying heap structure was moved to the C run-time libraries to support the new debugging features. As a result, the only Win32 platform that is supported by _heapwalk is Windows NT. When it is called by any other Win32 platform, _heapwalk returns _HEAPEND and sets errno to ENOSYS.

Example

/* HEAPWALK.C: This program "walks" the heap, starting
 * at the beginning (_pentry = NULL). It prints out each
 * heap entry's use, location, and size. It also prints
 * out information about the overall state of the heap as
 * soon as _heapwalk returns a value other than _HEAPOK.
 */

#include <stdio.h>
#include <malloc.h>

void heapdump( void );

void main( void )
{
   char *buffer;

   heapdump();
   if( (buffer = malloc( 59 )) != NULL )
   {
      heapdump();
      free( buffer );
   }
   heapdump();
}

void heapdump( void )
{
   _HEAPINFO hinfo;
   int heapstatus;
   hinfo._pentry = NULL;
   while( ( heapstatus = _heapwalk( &hinfo ) ) == _HEAPOK )
   { printf( "%6s block at %Fp of size %4.4X\n",
        ( hinfo._useflag == _USEDENTRY ? "USED" : "FREE" ),
          hinfo._pentry, hinfo._size );
   }

   switch( heapstatus )
   {
   case _HEAPEMPTY:
      printf( "OK - empty heap\n" );
      break;
   case _HEAPEND:
      printf( "OK - end of heap\n" );
      break;
   case _HEAPBADPTR:
      printf( "ERROR - bad pointer to heap\n" );
      break;
   case _HEAPBADBEGIN:
      printf( "ERROR - bad start of heap\n" );
      break;
   case _HEAPBADNODE:
      printf( "ERROR - bad node in heap\n" );
      break;
   }
}

Output

  USED block at 002C0004 of size 0014
  USED block at 002C001C of size 0054
  USED block at 002C0074 of size 0024
  USED block at 002C009C of size 0010
  USED block at 002C00B0 of size 0018
  USED block at 002C00CC of size 000C
  USED block at 002C00DC of size 001C
  USED block at 002C00FC of size 0010
  USED block at 002C0110 of size 0014
  USED block at 002C0128 of size 0010
  USED block at 002C013C of size 0028
  USED block at 002C0168 of size 0088
  USED block at 002C01F4 of size 001C
  USED block at 002C0214 of size 0014
  USED block at 002C022C of size 0010
  USED block at 002C0240 of size 0014
  USED block at 002C0258 of size 0010
  USED block at 002C026C of size 000C
  USED block at 002C027C of size 0010
  USED block at 002C0290 of size 0014
  USED block at 002C02A8 of size 0010
  USED block at 002C02BC of size 0010
  USED block at 002C02D0 of size 1000
  FREE block at 002C12D4 of size ED2C
OK - end of heap

Memory Allocation Routines

See Also _heapadd, _heapchk, _heapmin, _heapset


_hypot

Calculates the hypotenuse.

double _hypot( double x, double y );

Routine | Required Header | Compatibility
_hypot | <math.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_hypot returns the length of the hypotenuse if successful or INF (infinity) on overflow. The errno variable is set to ERANGE on overflow. You can modify error handling with _matherr.

Parameters

x, y

Floating-point values

Remarks

The _hypot function calculates the length of the hypotenuse of a right triangle, given the length of the two sides x and y. A call to _hypot is equivalent to the square root of x2 + y2.

Example

/* HYPOT.C: This program prints the
 * hypotenuse of a right  triangle.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 3.0, y = 4.0;

   printf( "If a right triangle has sides %2.1f and %2.1f, "
           "its hypotenuse is %2.1f\n", x, y, _hypot( x, y ) );
}

Output

If a right triangle has sides 3.0 and 4.0, its hypotenuse is 5.0

Floating-Point Support Routines

See Also _cabs, _matherr


_inp, _inpw, _inpd

Input a byte (_inp), a word (_inpw), or a double word (_inpd) from a port.

int _inp( unsigned short port );

unsigned short _inpw( unsigned short port );

unsigned long _inpd( unsigned short port );

Routine | Required Header | Compatibility
_inp | <conio.h> | Win 95
_inpw | <conio.h> | Win 95
_inpd | <conio.h> | Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The functions return the byte, word, or double word read from port. There is no error return.

Parameter

port

Port number

Remarks

The _inp, _inpw, and _inpd functions read a byte, a word, and a double word, respectively, from the specified input port. The input value can be any unsigned short integer in the range 0 – 65,535.

Console and Port I/O Routines

See Also _outp


is, isw Routines

isalnum, iswalnum | islower, iswlower
isalpha, iswalpha | isprint, iswprint
__isascii, iswascii | ispunct, iswpunct
iscntrl, iswcntrl | isspace, iswspace
__iscsym, __iscsymf | isupper, iswupper
isdigit, iswdigit | isxdigit, iswxdigit
isgraph, iswgraph | iswctype

Remarks

These routines test characters for specified conditions.

The is routines produce meaningful results for any integer argument from –1 (EOF) to UCHAR_MAX (0xFF), inclusive. The expected argument type is int.

Warning For the is routines, passing an argument of type char may yield unpredictable results. An SBCS or MBCS single-byte character of type char with a value greater than 0x7F is negative. If a char is passed, the compiler may convert the value to a signed int or a signed long. This value may be sign-extended by the compiler, with unexpected results.

The isw routines produce meaningful results for any integer value from – 1 (WEOF) to 0xFFFF, inclusive. The wint_t data type is defined in WCHAR.H as an unsigned short; it can hold any wide character or the wide-character end-of-file (WEOF) value.

For each of the is routines, the result of the test for the specified condition depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. In the “C” locale, the test conditions for the is routines are as follows:

isalnum

Alphanumeric (A – Z, a – z, or 0 – 9)

isalpha

Alphabetic (A – Z or a – z)

__isascii

ASCII character (0x00 – 0x7F)

iscntrl

Control character (0x00 – 0x1F or 0x7F)

__iscsym

Letter, underscore, or digit

__iscsymf

Letter or underscore

isdigit

Decimal digit (0 – 9)

isgraph

Printable character except space ( )

islower

Lowercase letter (a – z)

isprint

Printable character including space (0x20 – 0x7E)

ispunct

Punctuation character

isspace

White-space character (0x09 – 0x0D or 0x20)

isupper

Uppercase letter (A – Z)

isxdigit

Hexadecimal digit (A – F, a – f, or 0 – 9)

For the isw routines, the result of the test for the specified condition is independent of locale. The test conditions for the isw functions are as follows:

iswalnum

iswalpha or iswdigit

iswalpha

Any wide character that is one of an implementation-defined set for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. iswalpha returns true only for wide characters for which iswupper or iswlower is true.

iswascii

Wide-character representation of ASCII character (0x0000 – 0x007F).

iswcntrl

Control wide character.

iswctype

Character has property specified by the desc argument. For each valid value of the desc argument of iswctype, there is an equivalent wide-character classification routine, as shown in the following table:

Equivalence of iswctype( c, desc ) to Other isw Testing Routines

Value of desc Argument | iswctype( c, desc ) Equivalent
_ALPHA | iswalpha( c )
_ALPHA | _DIGIT | iswalnum( c )
_CONTROL | iswcntrl( c )
_DIGIT | iswdigit( c )
_ALPHA | _DIGIT | _PUNCT | iswgraph( c )
_LOWER | iswlower( c )
_ALPHA | _BLANK | _DIGIT | _PUNCT | iswprint( c )
_PUNCT | iswpunct( c )
_SPACE | iswspace( c )
_UPPER | iswupper( c )
_HEX | iswxdigit( c )

iswdigit

Wide character corresponding to a decimal-digit character.

iswgraph

Printable wide character except space wide character (L' ').

iswlower

Lowercase letter, or one of implementation-defined set of wide characters for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. iswlower returns true only for wide characters that correspond to lowercase letters.

iswprint

Printable wide character, including space wide character (L' ').

iswpunct

Printable wide character that is neither space wide character (L' ') nor wide character for which iswalnum is true.

iswspace

Wide character that corresponds to standard white-space character or is one of implementation-defined set of wide characters for which iswalnum is false. Standard white-space characters are: space (L' '), formfeed (L'\f'), newline (L'\n'), carriage return (L'\r'), horizontal tab (L'\t'), and vertical tab (L'\v').

iswupper

Wide character that is uppercase or is one of an implementation-defined set of wide characters for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. iswupper returns true only for wide characters that correspond to uppercase characters.

iswxdigit

Wide character that corresponds to a hexadecimal-digit character.

Example

/* ISFAM.C: This program tests all characters between 0x0
 * and 0x7F, then displays each character with abbreviations
 * for the character-type codes that apply.

 * Editor's note: the following output is significantly
 * shortened with the use of ellipses. This full output
 * is too long and repetitive.
 */

#include <stdio.h>
#include <ctype.h>

void main( void )
{
   int ch;
   for( ch = 0; ch <= 0x7F; ch++ )
   {
      printf( "%.2x  ", ch );
      printf( " %c", isprint( ch )  ? ch   : '\0' );
      printf( "%4s", isalnum( ch )  ? "AN" : "" );
      printf( "%3s", isalpha( ch )  ? "A"  : "" );
      printf( "%3s", __isascii( ch )  ? "AS" : "" );
      printf( "%3s", iscntrl( ch )  ? "C"  : "" );
      printf( "%3s", __iscsym( ch )  ? "CS "  : "" );
      printf( "%3s", __iscsymf( ch )  ? "CSF"  : "" );
      printf( "%3s", isdigit( ch )  ? "D"  : "" );
      printf( "%3s", isgraph( ch )  ? "G"  : "" );
      printf( "%3s", islower( ch )  ? "L"  : "" );
      printf( "%3s", ispunct( ch )  ? "PU" : "" );
      printf( "%3s", isspace( ch )  ? "S"  : "" );
      printf( "%3s", isprint( ch )  ? "PR" : "" );
      printf( "%3s", isupper( ch )  ? "U"  : "" );
      printf( "%3s", isxdigit( ch ) ? "X"  : "" );
      printf( "\n" );
   }
}

Output

00
01
02
03
04
05
06
07
08
09
0a
0b
0c
0d
0e
0f
10
11
12
13
14
15
16
17
18
19
1a
1b
1c
1d
1e
1f
20            AS                       S PR
21   !        AS              G    PU    PR
22   "        AS              G    PU    PR
23   #        AS              G    PU    PR
24   $        AS              G    PU    PR
25   %        AS              G    PU    PR
26   &        AS              G    PU    PR
27   '        AS              G    PU    PR
28   (        AS              G    PU    PR
29   )        AS              G    PU    PR
2a   *        AS              G    PU    PR
2b   +        AS              G    PU    PR
2c   ,        AS              G    PU    PR
2d   -        AS              G    PU    PR
2e   .        AS              G    PU    PR
2f   /        AS              G    PU    PR
30   0  AN    AS   CS      D  G          PR     X
31   1  AN    AS   CS      D  G          PR     X
32   2  AN    AS   CS      D  G          PR     X
33   3  AN    AS   CS      D  G          PR     X
34   4  AN    AS   CS      D  G          PR     X
35   5  AN    AS   CS      D  G          PR     X
36   6  AN    AS   CS      D  G          PR     X
37   7  AN    AS   CS      D  G          PR     X
38   8  AN    AS   CS      D  G          PR     X
.
.
.
39   9  AN    AS   CS      D  G          PR     X
3a   :        AS              G    PU    PR
3b   ;        AS              G    PU    PR
3c   <        AS              G    PU    PR
3d   =        AS              G    PU    PR
.
.
.
3e   >        AS              G    PU    PR
3f   ?        AS              G    PU    PR
40   @        AS              G    PU    PR
41   A  AN  A AS   CS CSF     G          PR  U  X
42   B  AN  A AS   CS CSF     G          PR  U  X
43   C  AN  A AS   CS CSF     G          PR  U  X
44   D  AN  A AS   CS CSF     G          PR  U  X
45   E  AN  A AS   CS CSF     G          PR  U  X
46   F  AN  A AS   CS CSF     G          PR  U  X
47   G  AN  A AS   CS CSF     G          PR  U
48   H  AN  A AS   CS CSF     G          PR  U
49   I  AN  A AS   CS CSF     G          PR  U
4a   J  AN  A AS   CS CSF     G          PR  U
4b   K  AN  A AS   CS CSF     G          PR  U
4c   L  AN  A AS   CS CSF     G          PR  U
4d   M  AN  A AS   CS CSF     G          PR  U
4e   N  AN  A AS   CS CSF     G          PR  U
4f   O  AN  A AS   CS CSF     G          PR  U
50   P  AN  A AS   CS CSF     G          PR  U
51   Q  AN  A AS   CS CSF     G          PR  U
52   R  AN  A AS   CS CSF     G          PR  U
53   S  AN  A AS   CS CSF     G          PR  U
54   T  AN  A AS   CS CSF     G          PR  U
55   U  AN  A AS   CS CSF     G          PR  U
56   V  AN  A AS   CS CSF     G          PR  U
57   W  AN  A AS   CS CSF     G          PR  U
58   X  AN  A AS   CS CSF     G          PR  U
59   Y  AN  A AS   CS CSF     G          PR  U
5a   Z  AN  A AS   CS CSF     G          PR  U
5b   [        AS              G    PU    PR
5c   \        AS              G    PU    PR
5d   ]        AS              G    PU    PR
5e   ^        AS              G    PU    PR
5f   _        AS   CS CSF     G    PU    PR
60   `        AS              G    PU    PR
61   a  AN  A AS   CS CSF     G  L       PR     X
62   b  AN  A AS   CS CSF     G  L       PR     X
63   c  AN  A AS   CS CSF     G  L       PR     X
64   d  AN  A AS   CS CSF     G  L       PR     X
65   e  AN  A AS   CS CSF     G  L       PR     X
66   f  AN  A AS   CS CSF     G  L       PR     X
67   g  AN  A AS   CS CSF     G  L       PR
68   h  AN  A AS   CS CSF     G  L       PR
69   i  AN  A AS   CS CSF     G  L       PR
6a   j  AN  A AS   CS CSF     G  L       PR
6b   k  AN  A AS   CS CSF     G  L       PR
6c   l  AN  A AS   CS CSF     G  L       PR
6d   m  AN  A AS   CS CSF     G  L       PR
6e   n  AN  A AS   CS CSF     G  L       PR
6f   o  AN  A AS   CS CSF     G  L       PR
70   p  AN  A AS   CS CSF     G  L       PR
71   q  AN  A AS   CS CSF     G  L       PR
72   r  AN  A AS   CS CSF     G  L       PR
73   s  AN  A AS   CS CSF     G  L       PR
74   t  AN  A AS   CS CSF     G  L       PR
75   u  AN  A AS   CS CSF     G  L       PR
76   v  AN  A AS   CS CSF     G  L       PR
77   w  AN  A AS   CS CSF     G  L       PR
78   x  AN  A AS   CS CSF     G  L       PR
79   y  AN  A AS   CS CSF     G  L       PR
7a   z  AN  A AS   CS CSF     G  L       PR
7b   {        AS              G    PU    PR
7c   |        AS              G    PU    PR
7d   }        AS              G    PU    PR
7e   ~        AS              G    PU    PR
7f

Character Classification Routines | Locale Routines

See Also setlocale, to Function Overview


isalnum, iswalnum

int isalnum( int c );

int iswalnum( wint_t c );

Each of these routines returns true if c is a particular representation of an alphanumeric character.

Routine | Required Header | Compatibility
isalnum | <ctype.h> | ANSI, Win 95, Win NT
iswalnum | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isalnum returns a non-zero value if either isalpha or isdigit is true for c, that is, if c is within the ranges A – Z, a – z, or 0 – 9. iswalnum returns a non-zero value if either iswalpha or iswdigit is true for c. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isalnum function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswalnum, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istalnum | isalnum | _ismbcalnum | iswalnum


isalpha, iswalpha

int isalpha( int c );

int iswalpha( wint_t c );

Each of these routines returns true if c is a particular representation of an alphabetic character.

Routine | Required Header | Compatibility
isalpha | <ctype.h> | ANSI, Win 95, Win NT
iswalpha | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isalpha returns a non-zero value if c is within the ranges A – Z or a – z. iswalpha returns a non-zero value only for wide characters for which iswupper or iswlower is true, that is, for any wide character that is one of an implementation-defined set for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isalpha function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswalpha, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istalpha | isalpha | _ismbcalpha | iswalpha


__isascii, iswascii

int __isascii( int c );

int iswascii( wint_t c );

Each of these routines returns true if c is a particular representation of an ASCII character.

Routine | Required Header | Compatibility
__isascii | <ctype.h> | Win 95, Win NT
iswascii | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

__isascii returns a non-zero value if c is an ASCII character (in the range 0x00 – 0x7F). iswascii returns a non-zero value if c is a wide-character representation of an ASCII character. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the __isascii function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswascii, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istascii | __isascii | __isascii | iswascii


iscntrl, iswcntrl

int iscntrl( int c );

int iswcntrl( wint_t c );

Each of these routines returns true if c is a particular representation of a control character.

Routine | Required Header | Compatibility
iscntrl | <ctype.h> | ANSI, Win 95, Win NT
iswcntrl | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

iscntrl returns a non-zero value if c is a control character (0x00 – 0x1F or 0x7F). iswcntrl returns a non-zero value if c is a control wide character. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the iscntrl function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswcntrl, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istcntrl | iscntrl | iscntrl | iswcntrl


__iscsym, __iscsymf

int __iscsym( int c );

int __iscsymf( int c );

Routine | Required Header | Compatibility
__iscsym | <ctype.h> | Win 95, Win NT
__iscsymf | <ctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

__iscsym returns a non-zero value if c is a letter, underscore, or digit. __iscsymf returns a non-zero value if c is a letter or an underscore. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the __iscsym function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For __iscsymf, the result of the test condition is independent of locale.

Parameter

c

Integer to test


isdigit, iswdigit

int isdigit( int c );

int iswdigit( wint_t c );

Each of these routines returns true if c is a particular representation of a decimal-digit character.

Routine | Required Header | Compatibility
isdigit | <ctype.h> | ANSI, Win 95, Win NT
iswdigit | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isdigit returns a non-zero value if c is a decimal digit (0 – 9). iswdigit returns a non-zero value if c is a wide character corresponding to a decimal-digit character. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isdigit function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswdigit, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istdigit | isdigit | _ismbcdigit | iswdigit


isgraph, iswgraph

int isgraph( int c );

int iswgraph( wint_t c );

Each of these routines returns true if c is a particular representation of a printable character other than a space.

Routine | Required Header | Compatibility
isgraph | <ctype.h> | ANSI, Win 95, Win NT
iswgraph | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isgraph returns a non-zero value if c is a printable character other than a space. iswgraph returns a non-zero value if c is a printable wide character other than a wide-character space. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isgraph function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswgraph, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istgraph | isgraph | _ismbcgraph | iswgraph


islower, iswlower

int islower( int c );

int iswlower( wint_t c );

Each of these routines returns true if c is a particular representation of a lowercase character.

Routine | Required Header | Compatibility
islower | <ctype.h> | ANSI, Win 95, Win NT
iswlower | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

islower returns a non-zero value if c is a lowercase character (a – z). iswlower returns a non-zero value if c is a wide character that corresponds to a lowercase letter, or if c is one of an implementation-defined set of wide characters for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the islower function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswlower, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istlower | islower | _ismbclower | iswlower


isprint, iswprint

int isprint( int c );

int iswprint( wint_t c );

Each of these routines returns true if c is a particular representation of a printable character.

Routine | Required Header | Compatibility
isprint | <ctype.h> | ANSI, Win 95, Win NT
iswprint | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isprint returns a nonzero value if c is a printable character, including the space character (0x20 – 0x7E). iswprint returns a nonzero value if c is a printable wide character, including the space wide character. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isprint function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswprint, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istprint | isprint | _ismbcprint | iswprint


ispunct, iswpunct

int ispunct( int c );

int iswpunct( wint_t c );

Each of these routines returns true if c is a particular representation of a punctuation character.

Routine | Required Header | Compatibility
ispunct | <ctype.h> | ANSI, Win 95, Win NT
iswpunct | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

ispunct returns a non-zero value for any printable character that is not a space character or a character for which isalnum is true. iswpunct returns a non-zero value for any printable wide character that is neither the space wide character nor a wide character for which iswalnum is true. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the ispunct function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswpunct, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istpunct | ispunct | _ismbcpunct | iswpunct


isspace, iswspace

int isspace( int c );

int iswspace( wint_t c );

Each of these routines returns true if c is a particular representation of a space character.

Routine | Required Header | Compatibility
isspace | <ctype.h> | ANSI, Win 95, Win NT
iswspace | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isspace returns a non-zero value if c is a white-space character (0x09 – 0x0D or 0x20). iswspace returns a non-zero value if c is a wide character that corresponds to a standard white-space character or is one of an implementation-defined set of wide characters for which iswalnum is false. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isspace function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswspace, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istspace | isspace | _ismbcspace | iswspace


isupper, iswupper

int isupper( int c );

int iswupper( wint_t c );

Each of these routines returns true if c is a particular representation of an uppercase letter.

Routine | Required Header | Compatibility
isupper | <ctype.h> | ANSI, Win 95, Win NT
iswupper | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isupper returns a non-zero value if c is an uppercase character (a – z). iswupper returns a non-zero value if c is a wide character that corresponds to an uppercase letter, or if c is one of an implementation-defined set of wide characters for which none of iswcntrl, iswdigit, iswpunct, or iswspace is true. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isupper function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For iswupper, the result of the test condition is independent of locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istupper | isupper | _ismbcupper | iswupper


iswctype

int iswctype( wint_t c, wctype_t desc );

iswctype tests c for the property specified by the desc argument. For each valid value of desc, there is an equivalent wide-character classification routine.

Routine | Required Header | Compatibility
iswctype | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

iswctype returns a nonzero value if c has the property specified by desc, or 0 if it does not. The result of the test condition is independent of locale.

Parameters

c

Integer to test

desc

Property to test for


isxdigit, iswxdigit

int isxdigit( int c );

int iswxdigit( wint_t c );

Each of these routines returns true if c is a particular representation of a hexadecimal digit.

Routine | Required Header | Compatibility
isxdigit | <ctype.h> | ANSI, Win 95, Win NT
iswxdigit | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isxdigit returns a non-zero value if c is a hexadecimal digit (A – F, a – f, or 0 – 9). iswxdigit returns a non-zero value if c is a wide character that corresponds to a hexadecimal digit character. Each of these routines returns 0 if c does not satisfy the test condition.

The result of the test condition for the isxdigit function depends on the LC_CTYPE category setting of the current locale; see setlocale for more information. For the “C” locale, the iswxdigit function does not provide support for Unicode fullwidth hexadecimal characters. The result of the test condition for iswxdigit is independent of any other locale.

Parameter

c

Integer to test

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istxdigit | isxdigit | isxdigit | iswxdigit


_isatty

int _isatty( int handle );

Routine | Required Header | Compatibility
_isatty | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_isatty returns a nonzero value handle is associated with a character device. Otherwise, _isatty returns 0.

Parameter

handle

Handle referring to device to be tested

Remarks

The _isatty function determines whether handle is associated with a character device (a terminal, console, printer, or serial port).

Example

/* ISATTY.C: This program checks to see whether
 * stdout has been redirected to a file.
 */

#include <stdio.h>
#include <io.h>

void main( void )
{
   if( _isatty( _fileno( stdout ) ) )
      printf( "stdout has not been redirected to a file\n" );
   else
      printf( "stdout has been redirected to a file\n");
}

Output

stdout has been redirected to a file

File Handling Routines


isleadbyte

int isleadbyte( int c );

Routine | Required Header | Compatibility
isleadbyte | <ctype.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

isleadbyte returns a nonzero value if the argument satisfies the test condition or 0 if it does not. In the “C” locale and in single-byte – character set (SBCS) locales, isleadbyte always returns 0.

Parameter

c

Integer to test

Remarks

The isleadbyte macro returns a nonzero value if its argument is the first byte of a multibyte character. isleadbyte produces a meaningful result for any integer argument from –1 (EOF) to UCHAR_MAX (0xFF), inclusive. The result of the test depends upon the LC_CTYPE category setting of the current locale; see setlocale for more information.

The expected argument type of isleadbyte is int; if a signed character is passed, the compiler may convert it to an integer by sign extension, yielding unpredictable results.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istleadbyte | Always returns false | _isleadbyte | Always returns false

Byte Classification Routines, Locale Routines

See Also _ismbb Routine Overview


_ismbb Routines

Each routine in the _ismbb family tests the given integer value c for a particular condition.

_ismbbalnum | _ismbbkpunct
_ismbbalpha | _ismbblead
_ismbbgraph | _ismbbprint
_ismbbkalnum | _ismbbpunct
_ismbbkana | _ismbbtrail
_ismbbkprint |

Remarks

Each routine in the _ismbb family tests the given integer value c for a particular condition. The test result depends on the multibyte code page in effect. By default, the multibyte code page is set to the system-default ANSI code page obtained from the operating system at program startup. You can query or change the multibyte code page in use with _getmbcp or _setmbcp, respectively.

The routines in the _ismbb family test the given integer c as follows.

Routine | Byte Test Condition
_ismbbalnum | isalnum || _ismbbkalnum
_ismbbalpha | isalpha || _ismbbkalnum
_ismbbgraph | Same as _ismbbprint, but _ismbbgraph does not include the space character (0x20).
_ismbbkalnum | Non-ASCII text symbol other than punctuation. For example, in code page 932 only, _ismbbkalnum tests for katakana alphanumeric.
_ismbbkana | Katakana (0xA1 – 0xDF). Specific to code page 932.
_ismbbkprint | Non-ASCII text or non-ASCII punctuation symbol. For example, in code page 932 only, _ismbbkprint tests for katakana alphanumeric or katakana punctuation (range: 0xA1 – 0xDF).
_ismbbkpunct | Non-ASCII punctuation. For example, in code page 932 only, _ismbbkpunct tests for katakana punctuation.
_ismbblead | First byte of multibyte character. For example, in code page 932 only, valid ranges are 0x81 – 0x9F, 0xE0 – 0xFC.
_ismbbprint | isprint || _ismbbkprint. ismbbprint includes the space character (0x20).
_ismbbpunct | ispunct || _ismbbkpunct
_ismbbtrail | Second byte of multibyte character. For example, in code page 932 only, valid ranges are 0x40 – 0x7E, 0x80 – 0xEC.

The following table shows the ORed values that compose the test conditions for these routines. The manifest constants _BLANK, _DIGIT, _LOWER, _PUNCT, and _UPPER are defined in CTYPE.H.

Routine | _BLANK | _DIGIT | LOWER | _PUNCT | UPPER | Non- ASCII Text | Non- ASCII Punct
_ismbbalnum | — | x | x | — | x | x | —
_ismbbalpha | — | — | x | — | x | x | —
_ismbbgraph | — | x | x | x | x | x | x
_ismbbkalnum | — | — | — | — | — | x | —
_ismbbkprint | — | — | — | — | — | x | x
_ismbbkpunct | — | — | — | — | — | — | x
_ismbbprint | x | x | x | x | x | x | x
_ismbbpunct | — | — | — | x | — | — | x

The _ismbb routines are implemented both as functions and as macros. For details on choosing either implementation, see Choosing Between Functions and Macros.

Byte Classification Routines | is, isw Function Overview

See Also _mbbtombc, _mbctombb


_ismbbalnum

int _ismbbalnum( unsigned int c );

Routine | Required Header | Compatibility
_ismbbalnum | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbalnum returns a nonzero value if the expression

isalnum || _ismbbkalnum

is true of c, or 0 if it is not.

Parameter

c

Integer to be tested


_ismbbalpha

int _ismbbalpha( unsigned int c );

Routine | Required Header | Compatibility
_ismbbalpha | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbalpha returns a nonzero value if the expression

isalpha || _ismbbkalnum

is true of c, or 0 if it is not.

Parameter

c

Integer to be tested


_ismbbgraph

int _ismbbgraph ( unsigned int c );

Routine | Required Header | Compatibility
_ismbbgraph | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbgraph returns a nonzero value if the expression

( _PUNCT | _UPPER | _LOWER | _DIGIT ) || _ismbbkprint

is true of c, or 0 if it is not.

Parameter

c

Integer to be tested


_ismbbkalnum

int _ismbbkalnum( unsigned int c );

Routine | Required Header | Compatibility
_ismbbkalnum | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbkalnum returns a nonzero value if the integer c is a non-ASCII text symbol other than punctuation, or 0 if it is not.

Parameter

c

Integer to be tested


_ismbbkana

int _ismbbkana( unsigned int c );

_ismbbkana tests for a katakana symbol and is specific to code page 932.

Routine | Required Header | Compatibility
_ismbbkana | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbkana returns a nonzero value if the integer c is a katakana symbol, or 0 if it is not.

Parameter

c

Integer to be tested


_ismbbkprint

int _ismbbkprint( unsigned int c );

Routine | Required Header | Compatibility
_ismbbkprint | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbkprint returns a nonzero value if the integer c is a non-ASCII text or non-ASCII punctuation symbol, or 0 if it is not. For example, in code page 932 only, _ismbbkprint tests for katakana alphanumeric or katakana punctuation (range: 0xA1 – 0xDF).

Parameter

c

Integer to be tested


_ismbbkpunct

int _ismbbkpunct( unsigned int c );

Routine | Required Header | Compatibility
_ismbbkpunct | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbkpunct returns a nonzero value if the integer c is a non-ASCII punctuation symbol, or 0 if it is not. For example, in code page 932 only, _ismbbkpunct tests for katakana punctuation.

Parameter

c

Integer to be tested


_ismbblead

int _ismbblead( unsigned int c );

Routine | Required Header | Optional Headers | Compatibility
_ismbblead | <mbctype.h> or <mbstring.h> | <ctype.h>,1 <limits.h>, <stdlib.h> | Win 95, Win NT

1 For manifest constants for the test conditions.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbblead returns a nonzero value if the integer c is the first byte of a multibyte character. For example, in code page 932 only, valid ranges are 0x81 – 0x9F and 0xE0 – 0xFC.

Parameter

c

Integer to be tested

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istlead | Always returns false | _ismbblead | Always returns false


_ismbbprint

int _ismbbprint( unsigned int c );

Routine | Required Header | Compatibility
_ismbbprint | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbprint returns a nonzero value if the expression

isprint || _ismbbkprint

is true of c, or 0 if it is not.

Parameter

c

Integer to be tested


_ismbbpunct

int _ismbbpunct( unsigned int c );

Routine | Required Header | Compatibility
_ismbbpunct | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbpunct returns a nonzero value if the integer c is a non-ASCII punctuation symbol.

Parameter

c

Integer to be tested


_ismbbtrail

int _ismbbtrail( unsigned int c );

Routine | Required Header | Optional Headers | Compatibility
_ismbbtrail | <mbctype.h> or <mbstring.h> | <ctype.h>,1 <limits.h>, <stdlib.h> | Win 95, Win NT

1 For manifest constants for the test conditions.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbbtrail returns a nonzero value if the integer c is the second byte of a multibyte character. For example, in code page 932 only, valid ranges are 0x40 – 0x7E and 0x80 – 0xEC.

Parameter

c

Integer to be tested


_ismbc Routines

Each of the _ismbc routines tests a given multibyte character c for a particular condition.

_ismbcalnum, _ismbcalpha, _ismbcdigit | _ismbcl0, _ismbcl1, _ismbcl2
_ismbcgraph, _ismbcprint, _ismbcpunct, _ismbcspace | _ismbclegal, _ismbcsymbol
_ismbchira, _ismbckata | _ismbclower, _ismbcupper

Remarks

The test result of each of the _ismbc routines depends on the multibyte code page in effect. Multibyte code pages have single byte alphabetic characters. By default, the multibyte code page is set to the system-default ANSI code page obtained from the operating system at program startup. You can query or change the multibyte code page in use with _getmbcp or _setmbcp, respectively.

Routine | Test Condition | Code Page 932 Example
_ismbcalnum | Alphanumeric | Returns true if and only if c is a single-byte representation of an ASCII English letter: See examples for _ismbcdigit and _ismbcalpha.
_ismbcalpha | Alphabetic | Returns true if and only if c is a single-byte representation of an ASCII English letter: See examples for _ismbcupper and _ismbclower; or a Katakana letter: 0xA6<=c<=0xDF.
_ismbcdigit | Digit | Returns true if and only if c is a single-byte representation of an ASCII digit: 0x30<=c<=0x39.
_ismbcgraph | Graphic | Returns true if and only if c is a single-byte representation of any ASCII or Katakana printable character except a white space ( ). See examples for _ismbcdigit, _ismbcalpha, and _ismbcpunct.
_ismbclegal | Valid multibyte character | Returns true if and only if the first byte of c is within ranges 0x81 – 0x9F or 0xE0 – 0xFC, while the second byte is within ranges 0x40 – 0x7E or 0x80 - FC.
_ismbclower | Lowercase alphabetic | Returns true if and only if c is a single-byte representation of an ASCII lowercase English letter: 0x61<=c<=0x7A.
_ismbcprint | Printable | Returns true if and only if c is a single-byte representation of any ASCII or Katakana printable character including a white space ( ): See examples for _ismbcspace, _ismbcdigit, _ismbcalpha, and _ismbcpunct.
_ismbcpunct | Punctuation | Returns true if and only if c is a single-byte representation of any ASCII or Katakana punctuation character.
_ismbcspace | Whitespace | Returns true if and only if c is a whitespace character: c=0x20 or 0x09<=c<=0x0D.
_ismbcsymbol | Multibyte symbol | Returns true if and only if 0x8141<=c<=0x81AC.
_ismbcupper | Uppercase alphabetic | Returns true if and only if c is a single-byte representation of an ASCII uppercase English letter: 0x41<=c<=0x5A.

Code Page 932 Specific

The following routines are specific to code page 932.

Routine | Test Condition (Code Page 932 Only)
_ismbchira | Double-byte Hiragana: 0x829F<=c<=0x82F1.
_ismbckata | Double-byte Katakana: 0x8340<=c<=0x8396.
_ismbcl0 | JIS non-Kanji: 0x8140<=c<=0x889E.
_ismbcl1 | JIS level-1: 0x889F<=c<=0x9872.
_ismbcl2 | JIS level-2: 0x989F<=c<=0xEA9E.

_ismbcl0, _ismbcl1, and _ismbcl2 check that the specified value c matches the test conditions described in the preceding table, but do not check that c is a valid multibyte character. If the lower byte is in the ranges 0x00 – 0x3F, 0x7F, or 0xFD – 0xFF, these functions return a nonzero value, indicating that the character satisfies the test condition. Use _ismbbtrail to test whether the multibyte character is defined.

END Code Page 932 Specific

Character Classification Routines

See Also is, isw Function Overview, _ismbb Function Overview


_ismbcalnum, _ismbcalpha, _ismbcdigit

int _ismbcalnum( unsigned int c );

int _ismbcalpha( unsigned int c );

int _ismbcdigit( unsigned int c );

Routine | Required Header | Compatibility
_ismbcalnum | <mbstring.h> | Win 95, Win NT
_ismbcalpha | <mbstring.h> | Win 95, Win NT
_ismbcdigit | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a nonzero value if the character satisfies the test condition or 0 if it does not. If c<= 255 and there is a corresponding _ismbb routine (for example, _ismbcalnum corresponds to _ismbbalnum), the result is the return value of the corresponding _ismbb routine.

Parameter

c

Character to be tested

Remarks

Each of these routines tests a given multibyte character for a given condition.

Routine | Test Condition | Code Page 932 Example
_ismbcalnum | Alphanumeric | Returns true if and only if c is a single-byte representation of an ASCII English letter: See examples for _ismbcdigit and _ismbcalpha.
_ismbcalpha | Alphabetic | Returns true if and only if c is a single-byte representation of an ASCII English letter: 0x41<=c<=0x5A or 0x61<=c<=0x7A; or a Katakana letter: 0xA6<=c<=0xDF.
_ismbcdigit | Digit | Returns true if and only if c is a single-byte representation of an ASCII digit: 0x30<=c<=0x39.

Character Classification Routines | _ismbc Function Overview

See Also is, isw Function Overview, _ismbb Function Overview


_ismbcgraph, _ismbcprint, _ismbcpunct, _ismbcspace

int _ismbcgraph( unsigned int c );

int _ismbcprint( unsigned int c );

int _ismbcpunct( unsigned int c );

int _ismbcspace( unsigned int c );

Routine | Required Header | Compatibility
_ismbcgraph | <mbstring.h> | Win 95, Win NT
_ismbcprint | <mbstring.h> | Win 95, Win NT
_ismbcpunct | <mbstring.h> | Win 95, Win NT
_ismbcspace | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a nonzero value if the character satisfies the test condition or 0 if it does not. If c<= 255 and there is a corresponding _ismbb routine (for example, _ismbcalnum corresponds to _ismbbalnum), the result is the return value of the corresponding _ismbb routine.

Parameter

c

Character to be tested

Remarks

Each of these functions tests a given multibyte character for a given condition.

Routine | Test Condition | Code Page 932 Example
_ismbcgraph | Graphic | Returns true if and only if c is a single-byte representation of any ASCII or Katakana printable character except a white space ( ).
_ismbcprint | Printable | Returns true if and only if c is a single-byte representation of any ASCII or Katakana printable character including a white space ( ).
_ismbcpunct | Punctuation | Returns true if and only if c is a single-byte representation of any ASCII or Katakana punctuation character.
_ismbcspace | Whitespace | Returns true if and only if c is a whitespace character: c=0x20 or 0x09<=c<=0x0D.

Character Classification Routines | _ismbc Function Overview

See Also is, isw Function Overview, _ismbb Function Overview


_ismbchira, _ismbckata

Code Page 932 Specific

int _ismbchira( unsigned int c );

int _ismbckata( unsigned int c );

Routine | Required Header | Compatibility
_ismbchira | <mbstring.h> | Win 95, Win NT
_ismbckata | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a nonzero value if the character satisfies the test condition or 0 if it does not. If c<= 255 and there is a corresponding _ismbb routine (for example, _ismbcalnum corresponds to _ismbbalnum), the result is the return value of the corresponding _ismbb routine.

Parameter

c

Character to be tested

Remarks

Each of these functions tests a given multibyte character for a given condition.

Routine | Test Condition (Code Page 932 Only)
_ismbchira | Double-byte Hiragana: 0x829F<=c<=0x82F1.
_ismbckata | Double-byte Katakana: 0x8340<=c<=0x8396.

End Code Page 932 Specific

Character Classification Routines | _ismbc Function Overview

See Also is, isw Function Overview, _ismbb Function Overview


_ismbcl0, _ismbcl1, _ismbcl2

Code Page 932 Specific

int _ismbcl0( unsigned int c );

int _ismbcl1( unsigned int c );

int _ismbcl2( unsigned int c );

Routine | Required Header | Compatibility
_ismbcl0 | <mbstring.h> | Win 95, Win NT
_ismbcl1 | <mbstring.h> | Win 95, Win NT
_ismbcl2 | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a nonzero value if the character satisfies the test condition or 0 if it does not. If c<= 255 and there is a corresponding _ismbb routine (for example, _ismbcalnum corresponds to _ismbbalnum), the result is the return value of the corresponding _ismbb routine.

Parameter

c

Character to be tested

Remarks

Each of these functions tests a given multibyte character for a given condition.

Routine | Test Condition (Code Page 932 Only)
_ismbcl0 | JIS non-Kanji: 0x8140<=c<=0x889E.
_ismbcl1 | JIS level-1: 0x889F<=c<=0x9872.
_ismbcl2 | JIS level-2: 0x989F<=c<=0xEA9E.

_ismbcl0, _ismbcl1, and _ismbcl2 check that the specified value c matches the test conditions described above, but do not check that c is a valid multibyte character. If the lower byte is in the ranges 0x00 – 0x3F, 0x7F, or 0xFD – 0xFF, these functions return a nonzero value, indicating that the character satisfies the test condition. Use _ismbbtrail to test whether the multibyte character is defined.

End Code Page 932 Specific

Character Classification Routines | _ismbc Function Overview

See Also is, isw Function Overview, _ismbb Function Overview


_ismbclegal, _ismbcsymbol

int _ismbclegal( unsigned int c );

int _ismbcsymbol( unsigned int c );

Routine | Required Header | Compatibility
_ismbclegal | <mbstring.h> | Win 95, Win NT
_ismbcsymbol | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a nonzero value if the character satisfies the test condition or 0 if it does not. If c<= 255 and there is a corresponding _ismbb routine (for example, _ismbcalnum corresponds to _ismbbalnum), the result is the return value of the corresponding _ismbb routine.

Parameter

c

Character to be tested

Remarks

Each of these functions tests a given multibyte character for a given condition.

Routine | Test Condition | Code Page 932 Example
_ismbclegal | Valid multibyte | Returns true if and only if the first byte of c is within ranges 0x81 – 0x9F or 0xE0 – 0xFC, while the second byte is within ranges 0x40 - 0x7E or 0x80 - FC.
_ismbcsymbol | Multibyte symbol | Returns true if and only if 0x8141<=c<=0x81AC.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_istlegal | Always returns false | _ismbclegal | Always returns false

Character Classification Routines | _ismbc Function Overview

See Also is, isw Function Overview, _ismbb Function Overview


_ismbclower, _ismbcupper

int _ismbclower( unsigned int c );

int _ismbcupper( unsigned int c );

Routine | Required Header | Compatibility
_ismbclower | <mbstring.h> | Win 95, Win NT
_ismbcupper | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a nonzero value if the character satisfies the test condition or 0 if it does not. If c<= 255 and there is a corresponding _ismbb routine (for example, _ismbcalnum corresponds to _ismbbalnum), the result is the return value of the corresponding _ismbb routine.

Parameter

c

Character to be tested

Remarks

Each of these functions tests a given multibyte character for a given condition.

Routine | Test Condition | Code Page 932 Example
_ismbclower | Lowercase alphabetic | Returns true if and only if c is a single-byte representation of an ASCII lowercase English letter: 0x61<=c<=0x7A.
_ismbcupper | Uppercase alphabetic | Returns true if and only if c is a single-byte representation of an ASCII uppercase English letter: 0x41<=c<=0x5A.

Character Classification Routines | _ismbc Function Overview

See Also is, isw Function Overview, _ismbb Function Overview


_ismbslead, _ismbstrail

int _ismbslead( const unsigned char *string, const unsigned char *current );

int _ismbstrail( const unsigned char *string, const unsigned char *current );

Routine | Required Header | Optional Headers | Compatibility
_ismbslead | <mbctype.h> or <mbstring.h> | <ctype.h>,1 <limits.h>, <stdlib.h> | Win 95, Win NT
_ismbstrail | <mbctype.h> or <mbstring.h> | <ctype.h>,1 <limits.h>, <stdlib.h> | Win 95, Win NT

1 For manifest constants for the test conditions.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ismbslead and _ismbstrail return –1 if the character is a lead or trail byte, respectively. Otherwise they return zero.

Parameters

string

Pointer to start of string or previous known lead byte

current

Pointer to position in string to be tested

Remarks

The _ismbslead and _ismbstrail routines perform context-sensitive tests for multibyte-character string lead and trail bytes; they determine whether a given substring pointer points to a lead byte or a trail byte. _ismbslead and _ismbstrail are slower than their _ismbblead and _ismbbtrail counterparts because they take the string context into account.

Character Classification Routines | _ismbc Function Overview

See Also is, isw Function Overview, _ismbb Function Overview


_isnan

Checks given double-precision floating-point value for not a number (NaN).

int _isnan( double x );

Routine | Required Header | Compatibility
_isnan | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_isnan returns a nonzero value (TRUE) if the argument x is a NaN; otherwise it returns 0 (FALSE).

Parameter

x

Double-precision floating-point value

Remarks

The _isnan function tests a given double-precision floating-point value x, returning a nonzero value if x is a NaN. A NaN is generated when the result of a floating-point operation cannot be represented in Institute of Electrical and Electronics Engineers (IEEE) format. For information about how a NaN is represented for output, see printf.

Floating-Point Support Routines

See Also _finite, _fpclass


_itoa, _i64toa, _ui64toa, _itow, _i64tow, _ui64tow

Convert an integer to a string.

char *_itoa( int value, char *string, int radix );

char *_i64toa( __int64 value, char *string, int radix );

char * _ui64toa( unsigned _int64 value, char *string, int radix );

wchar_t * _itow( int value, wchar_t *string, int radix );

wchar_t * _i64tow( __int64 value, wchar_t *string, int radix );

wchar_t * _ui64tow( unsigned __int64 value, wchar_t *string, int radix );

Routine | Required Header | Compatibility
_itoa | <stdlib.h> | Win 95, Win NT
_i64toa | <stdlib.h> | Win 95, Win NT
_ui64toa | <stdlib.h> | Win 95, Win NT
_itow | <stdlib.h> | Win 95, Win NT
_i64tow | <stdlib.h> | Win 95, Win NT
_ui64tow | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to string. There is no error return.

Parameters

value

Number to be converted

string

String result

radix

Base of value; must be in the range 2 – 36

Remarks

The _itoa, _i64toa, and _ui64toa function convert the digits of the given value argument to a null-terminated character string and stores the result (up to 33 bytes) in string. If radix equals 10 and value is negative, the first character of the stored string is the minus sign ( – ). _itow, _i64tow, and _ui64tow are wide-character versions of _itoa, _i64toa, and _ui64toa respectively.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_itot | _itoa | _itoa | _itow

Example

/* ITOA.C: This program converts integers of various
 * sizes to strings in various radixes.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[20];
   int  i = 3445;
   long l = -344115L;
   unsigned long ul = 1234567890UL;

   _itoa( i, buffer, 10 );
   printf( "String of integer %d (radix 10): %s\n", i, buffer );
   _itoa( i, buffer, 16 );
   printf( "String of integer %d (radix 16): 0x%s\n", i, buffer );
   _itoa( i, buffer, 2  );
   printf( "String of integer %d (radix 2): %s\n", i, buffer );

   _ltoa( l, buffer, 16 );
   printf( "String of long int %ld (radix 16): 0x%s\n", l,
                                                    buffer );

   _ultoa( ul, buffer, 16 );
   printf( "String of unsigned long %lu (radix 16): 0x%s\n", ul,
                                                    buffer );
}

Output

String of integer 3445 (radix 10): 3445
String of integer 3445 (radix 16): 0xd75
String of integer 3445 (radix 2): 110101110101
String of long int -344115 (radix 16): 0xfffabfcd
String of unsigned long 1234567890 (radix 16): 0x499602d2

Data Conversion Routines

See Also _ltoa, _ultoa


_kbhit

Checks the console for keyboard input.

int _kbhit( void );

Routine | Required Header | Compatibility
_kbhit | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_kbhit returns a nonzero value if a key has been pressed. Otherwise, it returns 0.

Remarks

The _kbhit function checks the console for a recent keystroke. If the function returns a nonzero value, a keystroke is waiting in the buffer. The program can then call _getch or _getche to get the keystroke.

Example

/* KBHIT.C: This program loops until the user
 * presses a key. If _kbhit returns nonzero, a
 * keystroke is waiting in the buffer. The program
 * can call _getch or _getche to get the keystroke.
 */

#include <conio.h>
#include <stdio.h>

void main( void )
{
   /* Display message until key is pressed. */
   while( !_kbhit() )
      _cputs( "Hit me!! " );

   /* Use _getch to throw key away. */
   printf( "\nKey struck was '%c'\n", _getch() );
   _getch();
}

Output

Hit me!! Hit me!! Hit me!! Hit me!! Hit me!! Hit me!! Hit me!!
Key struck was 'q'

Console and Port I/O Routines


labs

Calculates the absolute value of a long integer.

long labs( long n );

Routine | Required Header | Compatibility
labs | <stdlib.h> and <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The labs function returns the absolute value of its argument. There is no error return.

Parameter

n

Long-integer value

Example

/* ABS.C: This program computes and displays
 * the absolute values of several numbers.
 */

#include  <stdio.h>
#include  <math.h>
#include  <stdlib.h>

void main( void )
{
   int    ix = -4, iy;
   long   lx = -41567L, ly;
   double dx = -3.141593, dy;

   iy = abs( ix );
   printf( "The absolute value of %d is %d\n", ix, iy);

   ly = labs( lx );
   printf( "The absolute value of %ld is %ld\n", lx, ly);

   dy = fabs( dx );
   printf( "The absolute value of %f is %f\n", dx, dy );
}

Output

The absolute value of -4 is 4
The absolute value of -41567 is 41567
The absolute value of -3.141593 is 3.141593

Data Conversion Routines | Floating-Point Support

See Also abs, _cabs, fabs


ldexp

Computes a real number from the mantissa and exponent.

double ldexp( double x, int exp );

Routine | Required Header | Compatibility
ldexp | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The ldexp function returns the value of x * 2exp if successful. On overflow (depending on the sign of x), ldexp returns +/– HUGE_VAL; the errno variable is set to ERANGE.

Parameters

x

Floating-point value

exp

Integer exponent

Example

/* LDEXP.C */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 4.0, y;
   int p = 3;

   y = ldexp( x, p );
   printf( "%2.1f times two to the power of %d is %2.1f\n", x, p, y );
}

Output

4.0 times two to the power of 3 is 32.0

Floating-Point Support

See Also frexp, modf


ldiv

Computes the quotient and remainder of a long integer.

ldiv_t ldiv( long int numer, long int denom );

Routine | Required Header | Compatibility
ldiv | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

ldiv returns a structure of type ldiv_t that comprises both the quotient and the remainder.

Parameters

numer

Numerator

denom

Denominator

Remarks

The ldiv function divides numer by denom, computing the quotient and remainder. The sign of the quotient is the same as that of the mathematical quotient. The absolute value of the quotient is the largest integer that is less than the absolute value of the mathematical quotient. If the denominator is 0, the program terminates with an error message. ldiv is the same as div, except that the arguments of ldiv and the members of the returned structure are all of type long int.

The ldiv_t structure, defined in STDLIB.H, contains long int quot, the quotient, and long int rem, the remainder.

Example

/* LDIV.C: This program takes two long integers
 * as command-line arguments and displays the
 * results of the integer division.
 */

#include <stdlib.h>
#include <math.h>
#include <stdio.h>

void main( void )
{
   long x = 5149627, y = 234879;
   ldiv_t div_result;

   div_result = ldiv( x, y );
   printf( "For %ld / %ld, the quotient is ", x, y );
   printf( "%ld, and the remainder is %ld\n",
            div_result.quot, div_result.rem );
}

Output

For 5149627 / 234879, the quotient is 21, and the remainder is 217168

Floating-Point Support Routines

See Also div


_lfind

Performs a linear search for the specified key.

void *_lfind( const void *key, const void *base, unsigned int *num, unsigned int width, int (__cdecl *compare)(const void *elem1, const void *elem2) );

Routine | Required Header | Compatibility
_lfind | <search.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If the key is found, _lfind returns a pointer to the element of the array at base that matches key. If the key is not found, _lfind returns NULL.

Parameters

key

Object to search for

base

Pointer to base of search data

num

Number of array elements

width

Width of array elements

compare

Pointer to comparison routine

elem1

Pointer to key for search

elem2

Pointer to array element to be compared with key

Remarks

The _lfind function performs a linear search for the value key in an array of num elements, each of width bytes in size. Unlike bsearch, _lfind does not require the array to be sorted. The base argument is a pointer to the base of the array to be searched. The compare argument is a pointer to a user-supplied routine that compares two array elements and then returns a value specifying their relationship. _lfind calls the compare routine one or more times during the search, passing pointers to two array elements on each call. The compare routine must compare the elements then return nonzero, meaning the elements are different, or 0, meaning the elements are identical.

Example

/* LFIND.C: This program uses _lfind to search for
 * the word "hello" in the command-line arguments.
 */

#include <search.h>
#include <string.h>
#include <stdio.h>

int compare( const void *arg1, const void *arg2 );

void main( unsigned int argc, char **argv )
{
   char **result;
   char *key = "hello";

   result = (char **)_lfind( &key, argv,
                      &argc, sizeof(char *), compare );
   if( result )
      printf( "%s found\n", *result );
   else
      printf( "hello not found!\n" );
}

int compare(const void *arg1, const void *arg2 )
{
   return( _stricmp( * (char**)arg1, * (char**)arg2 ) );
}

Output

[C:\code]lfind Hello
Hello found

Searching and Sorting Routines

See Also bsearch, _lsearch, qsort


localeconv

Gets detailed information on locale settings.

struct lconv *localeconv( void );

Routine | Required Header | Compatibility
localeconv | <locale.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

localeconv returns a pointer to a filled-in object of type struct lconv. The values contained in the object can be overwritten by subsequent calls to localeconv and do not directly modify the object. Calls to setlocale with category values of LC_ALL, LC_MONETARY, or LC_NUMERIC overwrite the contents of the structure.

Remarks

The localeconv function gets detailed information about numeric formatting for the current locale. This information is stored in a structure of type lconv. The lconv structure, defined in LOCALE.H, contains the following members:

char *decimal_point

Decimal-point character for nonmonetary quantities.

char *thousands_sep

Character that separates groups of digits to left of decimal point for nonmonetary quantities.

char *grouping

Size of each group of digits in nonmonetary quantities.

char *int_curr_symbol

International currency symbol for current locale. First three characters specify alphabetic international currency symbol as defined in the ISO 4217 Codes for the Representation of Currency and Funds standard. Fourth character (immediately preceding null character) separates international currency symbol from monetary quantity.

char *currency_symbol

Local currency symbol for current locale.

char *mon_decimal_point

Decimal-point character for monetary quantities.

char *mon_thousands_sep

Separator for groups of digits to left of decimal place in monetary quantities.

char *mon_grouping

Size of each group of digits in monetary quantities.

char *positive_sign

String denoting sign for nonnegative monetary quantities.

char *negative_sign

String denoting sign for negative monetary quantities.

char int_frac_digits

Number of digits to right of decimal point in internationally formatted monetary quantities.

char frac_digits

Number of digits to right of decimal point in formatted monetary quantities.

char p_cs_precedes

Set to 1 if currency symbol precedes value for nonnegative formatted monetary quantity. Set to 0 if symbol follows value.

char p_sep_by_space

Set to 1 if currency symbol is separated by space from value for nonnegative formatted monetary quantity. Set to 0 if there is no space separation.

char n_cs_precedes

Set to 1 if currency symbol precedes value for negative formatted monetary quantity. Set to 0 if symbol succeeds value.

char n_sep_by_space

Set to 1 if currency symbol is separated by space from value for negative formatted monetary quantity. Set to 0 if there is no space separation.

char p_sign_posn

Position of positive sign in nonnegative formatted monetary quantities.

char n_sign_posn

Position of positive sign in negative formatted monetary quantities.

The char * members of the structure are pointers to strings. Any of these (other than char *decimal_point) that equals "" is either of zero length or is not supported in the current locale. The char members of the structure are nonnegative numbers. Any of these that equals CHAR_MAX is not supported in the current locale.

The elements of grouping and mon_grouping are interpreted according to the following rules.

CHAR_MAX

Do not perform any further grouping.

0

Use previous element for each of remaining digits.

n

Number of digits that make up current group. Next element is examined to determine size of next group of digits before current group.

The values for int_curr_symbol are interpreted according to the following rules:

  • The first three characters specify the alphabetic international currency symbol as defined in the ISO 4217 Codes for the Representation of Currency and Funds standard.

  • The fourth character (immediately preceding the null character) separates the international currency symbol from the monetary quantity.

The values for p_cs_precedes and n_cs_precedes are interpreted according to the following rules (the n_cs_precedes rule is in parentheses):

0

Currency symbol follows value for nonnegative (negative) formatted monetary value.

1

Currency symbol precedes value for nonnegative (negative) formatted monetary value.

The values for p_sep_by_space and n_sep_by_space are interpreted according to the following rules (the n_sep_by_space rule is in parentheses):

0

Currency symbol is separated from value by space for nonnegative (negative) formatted monetary value.

1

There is no space separation between currency symbol and value for nonnegative (negative) formatted monetary value.

The values for p_sign_posn and n_sign_posn are interpreted according to the following rules:

0

Parentheses surround quantity and currency symbol

1

Sign string precedes quantity and currency symbol

2

Sign string follows quantity and currency symbol

3

Sign string immediately precedes currency symbol

4

Sign string immediately follows currency symbol

Locale Routines

See Also setlocale, strcoll Functions, strftime, strxfrm


localtime

Converts a time value and corrects for the local time zone.

struct tm *localtime( const time_t *timer );

Routine | Required Header | Compatibility
localtime | <time.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

localtime returns a pointer to the structure result. If the value in timer represents a date before midnight, January 1, 1970, localtime returns NULL. The fields of the structure type tm store the following values, each of which is an int:

tm_sec

Seconds after minute (0 – 59)

tm_min

Minutes after hour (0 – 59)

tm_hour

Hours after midnight (0 – 23)

tm_mday

Day of month (1 – 31)

tm_mon

Month (0 – 11; January = 0)

tm_year

Year (current year minus 1900)

tm_wday

Day of week (0 – 6; Sunday = 0)

tm_yday

Day of year (0 – 365; January 1 = 0)

tm_isdst

Positive value if daylight saving time is in effect; 0 if daylight saving time is not in effect; negative value if status of daylight saving time is unknown. The C run-time library assumes the United States’s rules for implementing the calculation of Daylight Saving Time (DST).

Parameter

timer

Pointer to stored time

Remarks

The localtime function converts a time stored as a time_t value and stores the result in a structure of type tm. The long value timer represents the seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time (UTC). This value is usually obtained from the time function.

gmtime, mktime, and localtime all use a single statically allocated tm structure for the conversion. Each call to one of these routines destroys the result of the previous call.

localtime corrects for the local time zone if the user first sets the global environment variable TZ. When TZ is set, three other environment variables (_timezone, _daylight, and _tzname) are automatically set as well. See _tzset for a description of these variables. TZ is a Microsoft extension and not part of the ANSI standard definition of localtime.

Note The target environment should try to determine whether daylight saving time is in effect.

Example

/* LOCALTIM.C: This program uses time to get the current time
 * and then uses localtime to convert this time to a structure
 * representing the local time. The program converts the result
 * from a 24-hour clock to a 12-hour clock and determines the
 * proper extension (AM or PM).
 */

#include <stdio.h>
#include <string.h>
#include <time.h>

void main( void )
{
        struct tm *newtime;
        char am_pm[] = "AM";
        time_t long_time;

        time( &long_time );                /* Get time as long integer. */
        newtime = localtime( &long_time ); /* Convert to local time. */

        if( newtime->tm_hour > 12 )        /* Set up extension. */
                strcpy( am_pm, "PM" );
        if( newtime->tm_hour > 12 )        /* Convert from 24-hour */
                newtime->tm_hour -= 12;    /*   to 12-hour clock.  */
        if( newtime->tm_hour == 0 )        /*Set hour to 12 if midnight. */
                newtime->tm_hour = 12;

        printf( "%.19s %s\n", asctime( newtime ), am_pm );
}

Output

Tue Mar 23 11:28:17 AM

Time Management Routines

See Also asctime, ctime, _ftime, gmtime, time, _tzset


_locking

Locks or unlocks bytes of a file.

int _locking( int handle, int mode, long nbytes );

Routine | Required Header | Optional Headers | Compatibility
_locking | <io.h> and <sys/locking.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_locking returns 0 if successful. A return value of –1 indicates failure, in which case errno is set to one of the following values:

EACCES

Locking violation (file already locked or unlocked).

EBADF

Invalid file handle.

EDEADLOCK

Locking violation. Returned when the _LK_LOCK or _LK_RLCK flag is specified and the file cannot be locked after 10 attempts.

EINVAL

An invalid argument was given to _locking.

Parameters

handle

File handle

mode

Locking action to perform

nbytes

Number of bytes to lock

Remarks

The _locking function locks or unlocks nbytes bytes of the file specified by handle. Locking bytes in a file prevents access to those bytes by other processes. All locking or unlocking begins at the current position of the file pointer and proceeds for the next nbytes bytes. It is possible to lock bytes past end of file.

mode must be one of the following manifest constants, which are defined in LOCKING.H:

_LK_LOCK

Locks the specified bytes. If the bytes cannot be locked, the program immediately tries again after 1 second. If, after 10 attempts, the bytes cannot be locked, the constant returns an error.

_LK_NBLCK

Locks the specified bytes. If the bytes cannot be locked, the constant returns an error.

_LK_NBRLCK

Same as _LK_NBLCK.

_LK_RLCK

Same as _LK_LOCK.

_LK_UNLCK

Unlocks the specified bytes, which must have been previously locked.

Multiple regions of a file that do not overlap can be locked. A region being unlocked must have been previously locked. _locking does not merge adjacent regions; if two locked regions are adjacent, each region must be unlocked separately. Regions should be locked only briefly and should be unlocked before closing a file or exiting the program.

Example

/* LOCKING.C: This program opens a file with sharing. It locks
 * some bytes before reading them, then unlocks them. Note that the
 * program works correctly only if the file exists.
 */

#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/locking.h>
#include <share.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int  fh, numread;
   char buffer[40];

   /* Quit if can't open file or system doesn't
    * support sharing.
    */
   fh = _sopen( "locking.c", _O_RDWR, _SH_DENYNO,
                 _S_IREAD | _S_IWRITE );
   if( fh == -1 )
      exit( 1 );

   /* Lock some bytes and read them. Then unlock. */
   if( _locking( fh, LK_NBLCK, 30L ) != -1 )
   {
      printf( "No one can change these bytes while I'm reading them\n" );
      numread = _read( fh, buffer, 30 );
      printf( "%d bytes read: %.30s\n", numread, buffer );
      lseek( fh, 0L, SEEK_SET );
     _locking( fh, LK_UNLCK, 30L );
      printf( "Now I'm done. Do what you will with them\n" );
   }
   else
      perror( "Locking failed\n" );

   _close( fh );
}

Output

No one can change these bytes while I'm reading them
30 bytes read: /* LOCKING.C: This program ope
Now I'm done. Do what you will with them

File Handling Routines

See Also _creat, _open


log, log10

Calculates logarithms.

double log( double x );

double log10( double x );

Routine | Required Header | Compatibility
log | <math.h> | ANSI, Win 95, Win NT
log10 | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The log functions return the logarithm of x if successful. If x is negative, these functions return an indefinite (same as a quiet NaN). If x is 0, they return INF (infinite). You can modify error handling by using the _matherr routine.

Parameter

x

Value whose logarithm is to be found

Example

/* LOG.C: This program uses log and log10
 * to calculate the natural logarithm and
 * the base-10 logarithm of 9,000.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 9000.0;
   double y;

   y = log( x );
   printf( "log( %.2f ) = %f\n", x, y );
   y = log10( x );
   printf( "log10( %.2f ) = %f\n", x, y );
}

Output

log( 9000.00 ) = 9.104980
log10( 9000.00 ) = 3.954243

Floating-Point Support Routines

See Also exp, _matherr, pow


_logb

Extracts exponential value of double-precision floating-point argument.

double _logb( double x );

Routine | Required Header | Compatibility
_logb | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_logb returns the unbiased exponential value of x.

Parameter

x

Double-precision floating-point value

Remarks

The _logb function extracts the exponential value of its double-precision floating-point argument x, as though x were represented with infinite range. If the argument x is denormalized, it is treated as if it were normalized.

Floating-Point Support Routines

See Also frexp


longjmp

Restores stack environment and execution locale.

void longjmp( jmp_buf env, int value );

Routine | Required Header | Compatibility
longjmp | <setjmp.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

env

Variable in which environment is stored

value

Value to be returned to setjmp call

Remarks

The longjmp function restores a stack environment and execution locale previously saved in env by setjmp. setjmp and longjmp provide a way to execute a nonlocal goto; they are typically used to pass execution control to error-handling or recovery code in a previously called routine without using the normal call and return conventions.

A call to setjmp causes the current stack environment to be saved in env. A subsequent call to longjmp restores the saved environment and returns control to the point immediately following the corresponding setjmp call. Execution resumes as if value had just been returned by the setjmp call. The values of all variables (except register variables) that are accessible to the routine receiving control contain the values they had when longjmp was called. The values of register variables are unpredictable. The value returned by setjmp must be nonzero. If value is passed as 0, the value 1 is substituted in the actual return.

Call longjmp before the function that called setjmp returns; otherwise the results are unpredictable.

Observe the following restrictions when using longjmp:

  • Do not assume that the values of the register variables will remain the same. The values of register variables in the routine calling setjmp may not be restored to the proper values after longjmp is executed.

  • Do not use longjmp to transfer control out of an interrupt-handling routine unless the interrupt is caused by a floating-point exception. In this case, a program may return from an interrupt handler via longjmp if it first reinitializes the floating-point math package by calling _fpreset.

  • Be careful when using setjmp and longjmp in C++ programs. Because these functions do not support C++ object semantics, it is safer to use the C++ exception-handling mechanism.

Example

/* FPRESET.C: This program uses signal to set up a
 * routine for handling floating-point errors.
 */

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>

jmp_buf mark;              /* Address for long jump to jump to */
int     fperr;             /* Global error number */

void __cdecl fphandler( int sig, int num );   /* Prototypes */
void fpcheck( void );

void main( void )
{
   double n1, n2, r;
   int jmpret;
   /* Unmask all floating-point exceptions. */
    _control87( 0, _MCW_EM );
   /* Set up floating-point error handler. The compiler
    * will generate a warning because it expects
    * signal-handling functions to take only one argument.
    */
    if( signal( SIGFPE, fphandler ) == SIG_ERR )

   {
      fprintf( stderr, "Couldn't set SIGFPE\n" );
      abort();   }

   /* Save stack environment for return in case of error. First
    * time through, jmpret is 0, so true conditional is executed.
    * If an error occurs, jmpret will be set to -1 and false
    * conditional will be executed.
    */
   jmpret = setjmp( mark );
   if( jmpret == 0 )
   {
      printf( "Test for invalid operation - " );
      printf( "enter two numbers: " );
      scanf( "%lf %lf", &n1, &n2 );
      r = n1 / n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g / %4.3g = %4.3g\n", n1, n2, r );

      r = n1 * n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g * %4.3g = %4.3g\n", n1, n2, r );
   }
   else
      fpcheck();
}
/* fphandler handles SIGFPE (floating-point error) interrupt. Note
 * that this prototype accepts two arguments and that the
 * prototype for signal in the run-time library expects a signal
 * handler to have only one argument.
 *
 * The second argument in this signal handler allows processing of
 * _FPE_INVALID, _FPE_OVERFLOW, _FPE_UNDERFLOW, and
 * _FPE_ZERODIVIDE, all of which are Microsoft-specific symbols
 * that augment the information provided by SIGFPE. The compiler
 * will generate a warning, which is harmless and expected.

 */
void fphandler( int sig, int num )
{
   /* Set global for outside check since we don't want
    * to do I/O in the handler.
    */
   fperr = num;
   /* Initialize floating-point package. */
   _fpreset();
   /* Restore calling environment and jump back to setjmp. Return
    * -1 so that setjmp will return false for conditional test.
    */
   longjmp( mark, -1 );
}
void fpcheck( void )
{
   char fpstr[30];
   switch( fperr )
   {
   case _FPE_INVALID:
       strcpy( fpstr, "Invalid number" );
       break;
   case _FPE_OVERFLOW:
       strcpy( fpstr, "Overflow" );

       break;
   case _FPE_UNDERFLOW:
       strcpy( fpstr, "Underflow" );
       break;
   case _FPE_ZERODIVIDE:
       strcpy( fpstr, "Divide by zero" );
       break;
   default:
       strcpy( fpstr, "Other floating point error" );
       break;
   }
   printf( "Error %d: %s\n", fperr, fpstr );
}

Output

Test for invalid operation - enter two numbers: 5 0
Error 131: Divide by zero

Process and Environment Control Routines

See Also setjmp


_lrotl, _lrotr

Rotate bits to the left (_lrotl) or right (_lrotr).

unsigned long _lrotl( unsigned long value, int shift );

unsigned long _lrotr( unsigned long value, int shift );

Routine | Required Header | Compatibility
_lrotl | <stdlib.h> | Win 95, Win NT
_lrotr | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Both functions return the rotated value. There is no error return.

Parameters

value

Value to be rotated

shift

Number of bits to shift value

Remarks

The _lrotl and _lrotr functions rotate value by shift bits. _lrotl rotates the value left. _lrotr rotates the value right. Both functions “wrap” bits rotated off one end of value to the other end.

Example

/* LROT.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   unsigned long val = 0x0fac35791;

   printf( "0x%8.8lx rotated left eight times is 0x%8.8lx\n",
            val, _lrotl( val, 8 ) );
   printf( "0x%8.8lx rotated right four times is 0x%8.8lx\n",
            val, _lrotr( val, 4 ) );
}

Output

0xfac35791 rotated left eight times is 0xc35791fa
0xfac35791 rotated right four times is 0x1fac3579

Floating-Point Support Routines

See Also _rotl, _rotr


_lsearch

Performs a linear search for a value; adds to end of list if not found.

void *_lsearch( const void *key, void *base, unsigned int *num, unsigned int width, int (__cdecl *compare)(const void *elem1, const void *elem2) );

Routine | Required Header | Compatibility
_lsearch | <search.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If the key is found, _lsearch returns a pointer to the element of the array at base that matches key. If the key is not found, _lsearch returns a pointer to the newly added item at the end of the array.

Parameters

key

Object to search for

base

Pointer to base of array to be searched

num

Number of elements

width

Width of each array element

compare

Pointer to comparison routine

elem1

Pointer to key for search

elem2

Pointer to array element to be compared with key

Remarks

The _lsearch function performs a linear search for the value key in an array of num elements, each of width bytes in size. Unlike bsearch, _lsearch does not require the array to be sorted. If key is not found, _lsearch adds it to the end of the array and increments num.

The compare argument is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. _lsearch calls the compare routine one or more times during the search, passing pointers to two array elements on each call. compare must compare the elements, then return either nonzero, meaning the elements are different, or 0, meaning the elements are identical.

Example

/* LFIND.C: This program uses _lfind to search for
 * the word "hello" in the command-line arguments.
 */

#include <search.h>
#include <string.h>
#include <stdio.h>

int compare( const void *arg1, const void *arg2 );

void main( unsigned int argc, char **argv )
{
   char **result;
   char *key = "hello";

   result = (char **)_lfind( &key, argv,
                      &argc, sizeof(char *), compare );
   if( result )
      printf( "%s found\n", *result );
   else
      printf( "hello not found!\n" );
}

int compare(const void *arg1, const void *arg2 )
{
   return( _stricmp( * (char**)arg1, * (char**)arg2 ) );
}

Output

[C:\code]lfind Hello
Hello found

Searching and Sorting Routines

See Also bsearch, _lfind


_lseek, _lseeki64

Move a file pointer to the specified location.

long _lseek( int handle, long offset, int origin );

__int64 _lseeki64( int handle, __int64 offset, int origin );

Routine | Required Header | Compatibility
_lseek | <io.h> | Win 95, Win NT
_lseeki64 | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_lseek returns the offset, in bytes, of the new position from the beginning of the file. _lseeki64 returns the offset in a 64-bit integer. The function returns –1L to indicate an error and sets errno either to EBADF, meaning the file handle is invalid, or to EINVAL, meaning the value for origin is invalid or the position specified by offset is before the beginning of the file. On devices incapable of seeking (such as terminals and printers), the return value is undefined.

Parameters

handle

Handle referring to open file

offset

Number of bytes from origin

origin

Initial position

Remarks

The _lseek function moves the file pointer associated with handle to a new location that is offset bytes from origin. The next operation on the file occurs at the new location. The origin argument must be one of the following constants, which are defined in STDIO.H:

SEEK_SET

Beginning of file

SEEK_CUR

Current position of file pointer

SEEK_END

End of file

You can use _lseek to reposition the pointer anywhere in a file or beyond the end of the file.

Example

/* LSEEK.C: This program first opens a file named LSEEK.C.
 * It then uses _lseek to find the beginning of the file,
 * to find the current position in the file, and to find
 * the end of the file.
 */

#include <io.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int fh;
   long pos;               /* Position of file pointer */
   char buffer[10];

   fh = _open( "lseek.c", _O_RDONLY );

   /* Seek the beginning of the file: */
   pos = _lseek( fh, 0L, SEEK_SET );
   if( pos == -1L )
      perror( "_lseek to beginning failed" );
   else
      printf( "Position for beginning of file seek = %ld\n", pos );

   /* Move file pointer a little */
    _read( fh, buffer, 10 );

   /* Find current position: */
   pos = _lseek( fh, 0L, SEEK_CUR );
   if( pos == -1L )
      perror( "_lseek to current position failed" );
   else
      printf( "Position for current position seek = %ld\n", pos );

   /* Set the end of the file: */
   pos = _lseek( fh, 0L, SEEK_END );
   if( pos == -1L )
      perror( "_lseek to end failed" );
   else
      printf( "Position for end of file seek = %ld\n", pos );

   _close( fh );
}

Output

Position for beginning of file seek = 0
Position for current position seek = 10
Position for end of file seek = 1207

Low-Level I/O Routines

See Also fseek, _tell


_ltoa, _ltow

Convert a long integer to a string.

char *_ltoa( long value, char *string, int radix );

wchar_t *_ltow( long value, wchar_t *string, int radix );

Routine | Required Header | Compatibility
_ltoa | <stdlib.h> | Win 95, Win NT
_ltow | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to string. There is no error return.

Parameters

value

Number to be converted

string

String result

radix

Base of value

Remarks

The _ltoa function converts the digits of value to a null-terminated character string and stores the result (up to 33 bytes) in string. The radix argument specifies the base of value, which must be in the range 2 – 36. If radix equals 10 and value is negative, the first character of the stored string is the minus sign (–). _ltow is a wide-character version of _ltoa; the second argument and return value of _ltow are wide-character strings. Each of these functions is Microsoft-specific.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_ltot | _ltoa | _ltoa | _ltow

Example

/* ITOA.C: This program converts integers of various
 * sizes to strings in various radixes.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[20];
   int  i = 3445;
   long l = -344115L;
   unsigned long ul = 1234567890UL;

   _itoa( i, buffer, 10 );
   printf( "String of integer %d (radix 10): %s\n", i, buffer );
   _itoa( i, buffer, 16 );
   printf( "String of integer %d (radix 16): 0x%s\n", i, buffer );
   _itoa( i, buffer, 2  );
   printf( "String of integer %d (radix 2): %s\n", i, buffer );

   _ltoa( l, buffer, 16 );
   printf( "String of long int %ld (radix 16): 0x%s\n", l,
                                                    buffer );

   _ultoa( ul, buffer, 16 );
   printf( "String of unsigned long %lu (radix 16): 0x%s\n", ul,
                                                    buffer );
}

Output

String of integer 3445 (radix 10): 3445
String of integer 3445 (radix 16): 0xd75
String of integer 3445 (radix 2): 110101110101
String of long int -344115 (radix 16): 0xfffabfcd
String of unsigned long 1234567890 (radix 16): 0x499602d2

Data Conversion Routines

See Also _itoa, _ultoa


_makepath, _wmakepath

Create a path name from components.

void _makepath( char *path, const char *drive, const char *dir, const char *fname, const char *ext );

void _wmakepath( wchar_t *path, const wchar_t *drive, const wchar_t *dir, const wchar_t *fname, const wchar_t *ext );

Routine | Required Header | Compatibility
_makepath | <stdlib.h> | Win 95, Win NT
_wmakepath | <stdlib.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

path

Full path buffer

drive

Drive letter

dir

Directory path

fname

Filename

ext

File extension

Remarks

The _makepath function creates a single path and stores it in path. The path may include a drive letter, directory path, filename, and filename extension. _wmakepath is a wide-character version of _makepath; the arguments to _wmakepath are wide-character strings. _wmakepath and _makepath behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tmakepath | _makepath | _makepath | _wmakepath

The following arguments point to buffers containing the path elements:

drive

Contains a letter (A, B, and so on) corresponding to the desired drive and an optional trailing colon. _makepath inserts the colon automatically in the composite path if it is missing. If drive is a null character or an empty string, no drive letter and colon appear in the composite path string.

dir

Contains the path of directories, not including the drive designator or the actual filename. The trailing slash is optional, and either a forward slash (/) or a backslash (\) or both may be used in a single dir argument. If a trailing slash (/ or \) is not specified, it is inserted automatically. If dir is a null character or an empty string, no slash is inserted in the composite path string.

fname

Contains the base filename without any extensions. If fname is NULL or points to an empty string, no filename is inserted in the composite path string.

ext

Contains the actual filename extension, with or without a leading period (.). _makepath inserts the period automatically if it does not appear in ext. If ext is a null character or an empty string, no period is inserted in the composite path string.

The path argument must point to an empty buffer large enough to hold the complete path. Although there are no size limits on any of the fields that constitute path, the composite path must be no larger than the _MAX_PATH constant, defined in STDLIB.H. _MAX_PATH may be larger than the current operating-system version will handle.

Example

/* MAKEPATH.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char path_buffer[_MAX_PATH];
   char drive[_MAX_DRIVE];
   char dir[_MAX_DIR];
   char fname[_MAX_FNAME];
   char ext[_MAX_EXT];

   _makepath( path_buffer, "c", "\\sample\\crt\\", "makepath", "c" );
   printf( "Path created with _makepath: %s\n\n", path_buffer );
   _splitpath( path_buffer, drive, dir, fname, ext );
   printf( "Path extracted with _splitpath:\n" );
   printf( "  Drive: %s\n", drive );
   printf( "  Dir: %s\n", dir );
   printf( "  Filename: %s\n", fname );
   printf( "  Ext: %s\n", ext );
}

Output

Path created with _makepath: c:\sample\crt\makepath.c

Path extracted with _splitpath:
  Drive: c:
  Dir: \sample\crt\
  Filename: makepath
  Ext: .c

File Handling Routines

See Also _fullpath, _splitpath


malloc

Allocates memory blocks.

void *malloc( size_t size );

Routine | Required Header | Compatibility
malloc | <stdlib.h> and <malloc.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

malloc returns a void pointer to the allocated space, or NULL if there is insufficient memory available. To return a pointer to a type other than void, use a type cast on the return value. The storage space pointed to by the return value is guaranteed to be suitably aligned for storage of any type of object. If size is 0, malloc allocates a zero-length item in the heap and returns a valid pointer to that item. Always check the return from malloc, even if the amount of memory requested is small.

Parameter

size

Bytes to allocate

Remarks

The malloc function allocates a memory block of at least size bytes. The block may be larger than size bytes because of space required for alignment and maintenance information.

The startup code uses malloc to allocate storage for the _environ, envp, and argv variables. The following functions and their wide-character counterparts also call malloc:

calloc | fscanf | _getw | setvbuf
_exec functions | fseek | _popen | _spawn functions
fgetc | fsetpos | printf | _strdup
_fgetchar | _fullpath | putc | system
fgets | fwrite | putchar | _tempnam
fprintf | getc | _putenv | ungetc
fputc | getchar | puts | vfprintf
_fputchar | _getcwd | _putw | vprintf
fputs | _getdcwd | scanf |
fread | gets | _searchenv |

The C++ _set_new_mode function sets the new handler mode for malloc. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when malloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. To override the default, call

_set_new_mode(1)

early in your program, or link with NEWMODE.OBJ.

When the application is linked with a debug version of the C run-time libraries, malloc resolves to _malloc_dbg. For more information about how the heap is managed during the debugging process, see Using C Run-Time Library Debugging Support.

Example

/* MALLOC.C: This program allocates memory with
 * malloc, then frees the memory with free.
 */

#include <stdlib.h>         /* For _MAX_PATH definition */
#include <stdio.h>
#include <malloc.h>

void main( void )
{
   char *string;

   /* Allocate space for a path name */
   string = malloc( _MAX_PATH );
   if( string == NULL )
      printf( "Insufficient memory available\n" );
   else
   {
      printf( "Memory space allocated for path name\n" );
      free( string );
      printf( "Memory freed\n" );
   }
}

Output

Memory space allocated for path name
Memory freed

Memory Allocation Routines

See Also calloc, free, realloc


_matherr

Handles math errors.

int _matherr( struct _exception *except );

Routine | Required Header | Compatibility
_matherr | <math.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_matherr returns 0 to indicate an error or a non-zero value to indicate success. If _matherr returns 0, an error message can be displayed, and errno is set to an appropriate error value. If _matherr returns a nonzero value, no error message is displayed, and errno remains unchanged.

Parameter

except

Pointer to structure containing error information

Remarks

The _matherr function processes errors generated by the floating-point functions of the math library. These functions call _matherr when an error is detected.

For special error handling, you can provide a different definition of _matherr. If you use the dynamically linked version of the C run-time library (MSVCRT.DLL), you can replace the default _matherr routine in a client executable with a user-defined version. However, you cannot replace the default _matherr routine in a DLL client of MSVCRT.DLL.

When an error occurs in a math routine, _matherr is called with a pointer to an _exception type structure (defined in MATH.H) as an argument. The _exception structure contains the following elements:

int type

Exception type

char *name

Name of function where error occurred

double arg1, arg2

First and second (if any) arguments to function

double retval

Value to be returned by function

The type specifies the type of math error. It is one of the following values, defined in MATH.H:

_DOMAIN

Argument domain error.

_SING

Argument singularity.

_OVERFLOW

Overflow range error.

_PLOSS

Partial loss of significance.

_TLOSS

Total loss of significance.

_UNDERFLOW

The result is too small to be represented. (This condition is not currently supported.)

The structure member name is a pointer to a null-terminated string containing the name of the function that caused the error. The structure members arg1 and arg2 specify the values that caused the error. (If only one argument is given, it is stored in arg1.)

The default return value for the given error is retval. If you change the return value, it must specify whether an error actually occurred.

Example

/* MATHERR.C illustrates writing an error routine for math
 * functions. The error function must be:
 *      _matherr
 */

#include <math.h>
#include <string.h>
#include <stdio.h>

void main()
{
    /* Do several math operations that cause errors. The _matherr
     * routine handles _DOMAIN errors, but lets the system handle
     * other errors normally.
     */
    printf( "log( -2.0 ) = %e\n", log( -2.0 ) );
    printf( "log10( -5.0 ) = %e\n", log10( -5.0 ) );
    printf( "log( 0.0 ) = %e\n", log( 0.0 ) );
}

/* Handle several math errors caused by passing a negative argument
 * to log or log10 (_DOMAIN errors). When this happens, _matherr
 * returns the natural or base-10 logarithm of the absolute value
 * of the argument and suppresses the usual error message.
 */
int _matherr( struct _exception *except )
{
    /* Handle _DOMAIN errors for log or log10. */
    if( except->type == _DOMAIN )
    {
        if( strcmp( except->name, "log" ) == 0 )
        {
            except->retval = log( -(except->arg1) );
            printf( "Special: using absolute value: %s: _DOMAIN "
                     "error\n", except->name );
            return 1;
        }
        else if( strcmp( except->name, "log10" ) == 0 )
        {
            except->retval = log10( -(except->arg1) );
            printf( "Special: using absolute value: %s: _DOMAIN "
                     "error\n", except->name );
            return 1;
        }
    }
    else
    {
        printf( "Normal: " );
        return 0;    /* Else use the default actions */
    }
}

Output

Special: using absolute value: log: _DOMAIN error
log( -2.0 ) = 6.931472e-001
Special: using absolute value: log10: _DOMAIN error
log10( -5.0 ) = 6.989700e-001
Normal: log( 0.0 ) = -1.#INF00e+000


__max

Returns the larger of two values.

type __max( type a, type b );

Routine | Required Header | Compatibility
_max | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

__max returns the larger of its arguments.

Parameters

type

Any numeric data type

a, b

Values of any numeric type to be compared

Remarks

The __max macro compares two values and returns the value of the larger one. The arguments can be of any numeric data type, signed or unsigned. Both arguments and the return value must be of the same data type.

Example

/* MINMAX.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int a = 10;
   int b = 21;

   printf( "The larger of %d and %d is %d\n",  a, b, __max( a, b ) );
   printf( "The smaller of %d and %d is %d\n", a, b, __min( a, b ) );
}

Output

The larger of 10 and 21 is 21
The smaller of 10 and 21 is 10

Floating-Point Support Routines

See Also __min


_mbbtombc

unsigned short _mbbtombc( unsigned short c );

Routine | Required Header | Compatibility
_mbbtombc | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If _mbbtombc successfully converts c, it returns a multibyte character; otherwise it returns c.

Parameter

c

Single-byte character to convert.

Remarks

The _mbbtombc function converts a given single-byte multibyte character to a corresponding double-byte multibyte character. Characters must be within the range 0x20 – 0x7E or 0xA1 – 0xDF to be converted.

In earlier versions, _mbbtombc was called hantozen. For new code, use _mbbtombc instead.

Data Conversion Routines

See Also _mbctombb


_mbbtype

int _mbbtype( unsigned char c, int type );

Routine | Required Header | Optional Headers | Compatibility
_mbbtype | <mbstring.h> | <mbctype.h>1 | Win 95, Win NT

1 For definitions of manifest constants used as return values.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbbtype returns the type of byte within a string. This decision is context-sensitive as specified by the value of type, which provides the control test condition. type is the type of the previous byte in the string.The manifest constants in the following table are defined in MBCTYPE.H.

Value of type | _mbbtype Tests For | Return Value | c
Any value except 1 | Valid single byte or lead byte | _MBC_SINGLE (0) | Single byte (0x20 – 0x7E, 0xA1 – 0xDF)
Any value except 1 | Valid single byte or lead byte | _MBC_LEAD (1) | Lead byte of multibyte character (0x81 – 0x9F, 0xE0 – 0xFC)
Any value except 1 | Valid single-byte or lead byte | _MBC_ILLEGAL ( –1) | Invalid character (any value except 0x20 – 0x7E, 0xA1 – 0xDF, 0x81 – 0x9F, 0xE0 – 0xFC
1 | Valid trail byte | _MBC_TRAIL (2) | Trailing byte of multibyte character (0x40 – 0x7E, 0x80 – 0xFC)
1 | Valid trail byte | _MBC_ILLEGAL ( –1) | Invalid character (any value except 0x20 – 0x7E, 0xA1 – 0xDF, 0x81 – 0x9F, 0xE0 – 0xFC

Parameters

c

Character to test

type

Type of byte to test for

Remarks

The _mbbtype function determines the type of a byte in a multibyte character. If the value of type is any value except 1, _mbbtype tests for a valid single-byte or lead byte of a multibyte character. If the value of type is 1, _mbbtype tests for a valid trail byte of a multibyte character.

In earlier versions, _mbbtype was called chkctype. For new code, _mbbtype use instead.

Byte Classification


_mbccpy

void _mbccpy( unsigned char *dest, const unsigned char *src );

Routine | Required Header | Compatibility
_mbccpy | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

dest

Copy destination

src

Multibyte character to copy

Remarks

The _mbccpy function copies one multibyte character from src to dest. If src does not point to the lead byte of a multibyte character as determined by an implicit call to _ismbblead, no copy is performed.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tccpy | Maps to macro or inline function | _mbccpy | Maps to macro or inline function

Locale Routines | Interpretation of Multibyte-Character Sequences

See Also _mbclen


_mbcjistojms, _mbcjmstojis

unsigned int _mbcjistojms( unsigned int c );

unsigned int _mbcjmstojis( unsigned int c );

Routine | Required Header | Compatibility
_mbcjistojms | <mbstring.h> | Win 95, Win NT
_mbcjmstojis | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbcjistojms and _mbcjmstojis return a converted character. Otherwise they return 0.

Parameter

c

Character to convert

Remarks

The _mbcjistojms function converts a Japan Industry Standard (JIS) character to a Microsoft Kanji (Shift JIS) character. The character is converted only if the lead and trail bytes are in the range 0x21 – 0x7E.

The _mbcjmstojis function converts a Shift JIS character to a JIS character. The character is converted only if the lead byte is in the range 0x81 – 0x9F or 0xE0 – 0xFC, and the trail byte is in the range 0x40 – 0x7E or 0x80 – 0xFC.

The value c should be a 16-bit value whose upper eight bits represent the lead byte of the character to convert and whose lower eight bits represent the trail byte.

In earlier versions, _mbcjistojms and _mbcjmstojis were called jistojms and jmstojis, repectively. _mbcjistojms and _mbcjmstojis should be used instead.

Data Conversion Routines

See Also _ismbb Routines


_mbclen, mblen

Get the length and determine the validity of a multibyte character.

size_t _mbclen( const unsigned char *c );

int mblen( const char *mbstr, size_t count );

Routine | Required Header | Compatibility
_mbclen | <mbstring.h> | Win 95, Win NT
mblen | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbclen returns 1 or 2, according to whether the multibyte character c is one or two bytes long. There is no error return for _mbclen. If mbstr is not NULL, mblen returns the length, in bytes, of the multibyte character. If mbstr is NULL, or if it points to the wide-character null character, mblen returns 0. If the object that mbstr points to does not form a valid multibyte character within the first count characters, mblen returns –1.

Parameters

c

Multibyte character

mbstr

Address of multibyte-character byte sequence

count

Number of bytes to check

Remarks

The _mbclen function returns the length, in bytes, of the multibyte character c. If c does not point to the lead byte of a multibyte character as determined by an implicit call to _ismbblead, the result of _mbclen is unpredictable.

mblen returns the length in bytes of mbstr if it is a valid multibyte character. It examines count or fewer bytes contained in mbstr, but not more than MB_CUR_MAX bytes. mblen determines multibyte-character validity according to the LC_CTYPE category setting of the current locale. For more information on the LC_CTYPE category, see setlocale.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tclen | Maps to macro or inline function | _mbclen | Maps to macro or inline function

Example

/* MBLEN.C illustrates the behavior of the mblen function
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
    int      i;
    char    *pmbc = (char *)malloc( sizeof( char ) );
    wchar_t  wc   = L'a';

    printf( "Convert wide character to multibyte character:\n" );
    i = wctomb( pmbc, wc );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tMultibyte character: %x\n\n", pmbc );

    i = mblen( pmbc, MB_CUR_MAX );
    printf( "Length in bytes of multibyte character %x: %u\n", pmbc, i );

    pmbc = NULL;
    i = mblen( pmbc, MB_CUR_MAX );
    printf( "Length in bytes of NULL multibyte character %x: %u\n", pmbc, i );
}

Output

Convert wide character to multibyte character:
   Characters converted: 1
   Multibyte character: 2c02cc

Length in bytes of multibyte character 2c02cc: 1
Length in bytes of NULL multibyte character 0: 0

Character Classification Routines | Locale Routines | Interpretation of Multibyte-Character Sequences

See Also _mbccpy, _mbslen


_mbctohira, _mbctokata

unsigned int _mbctohira( unsigned int c );

unsigned int _mbctokata( unsigned int c );

Routine | Required Header | Compatibility
_mbctohira | <mbstring.h> | Win 95, Win NT
_mbctokata | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the converted character c, if possible. Otherwise it returns the character c unchanged.

Parameter

c

Multibyte character to convert

Remarks

The _mbctohira and _mbctohira functions test a character c and, if possible, apply one of the following conversions.

Routine | Converts
_mbctohira | Multibyte katakana to multibyte hiragana
_mbctokata | Multibyte hiragana to multibyte katakana

In previous versions, _mbctohira was called jtohira and _mbctokata was called jtokata. For new code, use the new names instead.

Data Conversion Routines

See Also _mbcjistojms, _mbctolower, _mbctombb


_mbctolower, _mbctoupper

unsigned int _mbctolower( unsigned int c );

unsigned int _mbctoupper( unsigned int c );

Routine | Required Header | Compatibility
_mbctolower | <mbstring.h> | Win 95, Win NT
_mbctoupper | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the converted character c, if possible. Otherwise it returns the character c unchanged.

Parameter

c

Multibyte character to convert

Remarks

The _mbctolower and _mbctoupper functions test a character c and, if possible, apply one of the following conversions.

Routine | Converts
_mbctolower | Uppercase character to lowercase character
_mbctoupper | Lowercase character to uppercase character

In previous versions, _mbctolower was called jtolower, and _mbctoupper was called jtoupper. For new code, use the new names instead.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_totlower | tolower | _mbctolower | towlower
_totupper | toupper | _mbctoupper | towupper

Data Conversion Routines

See Also _mbbtombc, _mbcjistojms, _mbctohira, _mbctombb


_mbctombb

unsigned int _mbctombb( unsigned int c );

Routine | Required Header | Compatibility
_mbctombb | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _mbctombb returns the single-byte character that corresponds to c; otherwise it returns c.

Parameter

c

Multibyte character to convert.

Remarks

The _mbctombb function converts a given multibyte character to a corresponding single-byte multibyte character. Characters must correspond to single-byte characters within the range 0x20 – 0x7E or 0xA1 – 0xDF to be converted.

In previous versions, _mbctombb was called zentohan. Use _mbctombb instead.

Data Conversion Routines

See Also _mbbtombc, _mbcjistojms, _mbctohira, _mbctolower


_mbsbtype

int _mbsbtype( const unsigned char *mbstr, size_t count );

Routine | Required Header | Optional Headers | Compatibility
_mbsbtype | <mbstring.h> | <mbctype.h>1 | Win 95, Win NT

1 For manifest constants used as return values.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbsbtype returns an integer value indicating the result of the test on the specified byte. The manifest constants in the following table are defined in MBCTYPE.H.

Return Value | Byte Type
_MBC_SINGLE (0) | Single-byte character. For example, in code page 932, _mbsbtype returns 0 if the specified byte is within the range 0x20 – 0x7E or 0xA1 – 0xDF.
_MBC_LEAD (1) | Lead byte of multibyte character. For example, in code page 932, _mbsbtype returns 1 if the specified byte is within the range 0x81 – 0x9F or 0xE0 – 0xFC.
_MBC_TRAIL (2) | Trailing byte of multibyte character. For example, in code page 932, _mbsbtype returns 2 if the specified byte is within the range 0x40 – 0x7E or 0x80 – 0xFC.
_MBC_ILLEGAL (–1) | Invalid character, or NULL byte found before the byte at offset count in mbstr.

Parameters

mbstr

Address of a sequence of multibyte characters

count

Byte offset from head of string

Remarks

The _mbsbtype function determines the type of a byte in a multibyte character string. The function examines only the byte at offset count in mbstr, ignoring invalid characters before the specified byte.

Byte Classification


_mbsdec, _strdec, _wcsdec

unsigned char *_mbsdec( const unsigned char *start, const unsigned char *current );

Routine | Required Header | Optional Headers | Compatibility
_mbsdec | <mbstring.h> | <mbctype.h> | Win 95, Win NT
_strdec | <tchar.h> |  | Win 95, Win NT
_wcsdec | <tchar.h> |  | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbsdec, _strdec and _wcsdec each return a pointer to the character that immediately precedes current; _mbsdec returns NULL if the value of start is greater than or equal to that of current. _tcsdec maps to one of these functions and its return value depends on the mapping.

Parameters

start

Pointer to first byte of any multibyte character in the source string; start must precede current in the source string

current

Pointer to first byte of any multibyte character in the source string; current must follow start in the source string

Remarks

The _mbsdec function returns a pointer to the first byte of the multibyte-character that immediately precedes current in the string that contains start. _mbsdec recognizes multibyte-character sequences according to the multibyte code page currently in use.

The generic-text function _tcsdec, defined in TCHAR.H, maps to _mbsdec if the _MBCS preprocessor definition has been specified, or to _wcsdec if _UNICODE has been defined. _tcsdec when used with the appropriate preprocessor definition, lets you generate code that will work regardless of the width of character strings. Otherwise _tcsdec maps to _strdec. _strdec and _wcsdec are single-byte character and wide-character versions of _mbsdec. _strdec and _wcsdec are provided only for this mapping and should not be used otherwise. For more information, see Using Generic-Text Mappings and Appendix B, Generic-Text Mappings.

String Manipulation Routines

Example

The following code snippet shows a use of _tcsdec.

   const TCHAR *str = _T("some text");
   const TCHAR *str2;
   TCHAR *answer;
   str2 = str;
   str2++;
   answer = _tcsdec( str, str2 );

The following code snippet shows a use of _mbsdec.

   char *str = "some text";
   char *str2;
   unsigned char *answer;
   str2 = str;
   str2++;
   answer = _mbsdec( reinterpret_cast<unsigned char *>( str ), reinterpret_cast<unsigned char *>( str2 ));

See Also _mbsinc, _mbsnextc, _mbsninc


_mbsinc, _strinc, _wcsinc

unsigned char *_mbsinc( const unsigned char *current );

Routine | Required Header | Compatibility
_mbsinc | <mbstring.h> | Win 95, Win NT
_strinc | <tchar.h> | Win 95, Win NT
_wcsinc | <tchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a pointer to the character that immediately follows current.

Parameter

current

Character pointer

Remarks

The _mbsinc function returns a pointer to the first byte of the multibyte character that immediately follows current. _mbsinc recognizes multibyte-character sequences according to the multibyte code page currently in use.

The generic-text function _tcsinc, defined in TCHAR.H, maps to _mbsinc if _MBCS has been defined, or to _wcsinc if _UNICODE has been defined. Otherwise _tcsinc maps to _strinc. _strinc and _wcsinc are single-byte character and wide-character versions of _mbsinc. _strinc and _wcsinc are provided only for this mapping and should not be used otherwise. For more information, see Using Generic-Text Mappings and Appendix B, Generic-Text Mappings.

String Manipulation Routines

See Also _mbsdec, _mbsnextc, _mbsninc


_mbsnbcat

unsigned char *_mbsnbcat( unsigned char *dest, const unsigned char *src, size_t count );

Routine | Required Header | Compatibility
_mbsnbcat | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbsnbcat returns a pointer to the destination string. No return value is reserved to indicate an error.

Parameters

dest

Null-terminated multibyte-character destination string

src

Null-terminated multibyte-character source string

count

Number of bytes from src to append to dest

Remarks

The _mbsnbcat function appends, at most, the first count bytes of src to dest. If the byte immediately preceding the null character in dest is a lead byte, the initial byte of src overwrites this lead byte. Otherwise the initial byte of src overwrites the terminating null character of dest. If a null byte appears in src before count bytes are appended, _mbsnbcat appends all bytes from src, up to the null character. If count is greater than the length of src, the length of src is used in place of count. The resulting string is terminated with a null character. If copying takes place between strings that overlap, the behavior is undefined.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncat | strncat | _mbsnbcat | wcsncat

String Manipulation Routines

See Also _mbsnbcmp, _mbsnbcnt, _mbsnccnt, _mbsnbcpy, _mbsnbicmp, _mbsnbset, strncat


_mbsnbcmp

int _mbsnbcmp( const unsigned char *string1, const unsigned char string2, size_t count );

Routine | Required Header | Compatibility
_mbsnbcmp | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relation of the substrings of string1 and string.

Return Value | Description
< 0 | string1 substring less than string2 substring
0 | string1 substring identical to string2 substring
> 0 | string1 substring greater than string2 substring

On an error, _mbsnbcmp returns _NLSCMPERROR, which is defined in STRING.H and MBSTRING.H.

Parameters

string1, string2

Strings to compare

count

Number of bytes to compare

Remarks

The _mbsnbcmp function lexicographically compares, at most, the first count bytes in string1 and string2 and returns a value indicating the relationship between the substrings. _mbsnbcmp is a case-sensitive version of _mbsnbicmp. Unlike strcoll, _mbsnbcmp is not affected by locale. _mbsnbcmp recognizes multibyte-character sequences according to the current multibyte code page.

_mbsnbcmp is similar to _mbsncmp, except that _mbsnbcmp compares strings by characters rather than by bytes.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncmp | strncmp | _mbsnbcmp | wcsncmp

Example

/* STRNBCMP.C */
#include <mbstring.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown fox jumps over the lazy dog";

void main( void )
{
   char tmp[20];
   int result;
   printf( "Compare strings:\n\t\t%s\n\t\t%s\n\n", string1, string2 );
   printf( "Function:\t_mbsnbcmp (first 10 characters only)\n" );
   result = _mbsncmp( string1, string2 , 10 );
   if( result > 0 )
      _mbscpy( tmp, "greater than" );
   else if( result < 0 )
      _mbscpy( tmp, "less than" );
   else
      _mbscpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
   printf( "Function:\t_mbsnicmp _mbsnicmp (first 10 characters only)\n" );
   result = _mbsnicmp( string1, string2, 10 );
   if( result > 0 )
      _mbscpy( tmp, "greater than" );
   else if( result < 0 )
      _mbscpy( tmp, "less than" );
   else
      _mbscpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
}

Output

Compare strings:
      The quick brown dog jumps over the lazy fox
      The QUICK brown fox jumps over the lazy dog

Function:   _mbsnbcmp (first 10 characters only)
Result:      String 1 is greater than string 2

Function:   _mbsnicmp (first 10 characters only)
Result:      String 1 is equal to string 2

String Manipulation Routines

See Also _mbsnbcat, _mbsnbicmp, strncmp, _strnicmp


_mbsnbcnt, _mbsnccnt, _strncnt, _wcsncnt

Return number of characters or bytes within a supplied count

size_t _mbsnbcnt( const unsigned char *string, size_t number );

size_t _mbsnccnt( const unsigned char *string, size_t number );

Routine | Required Header | Compatibility
_mbsnbcnt | <mbstring.h> | Win 95, Win NT
_mbsnccnt | <mbstring.h> | Win 95, Win NT
_strncnt | <tchar.h> | Win 95, Win NT
_wcsncnt | <tchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbsnbcnt returns the number of bytes found in the first number of multibyte characters of string. _mbsnccnt returns the number of characters found in the first number of bytes of string. If a NULL character is encountered before the examination of string has completed, they return the number of bytes or characters found before the NULL character. If string consists of fewer than number characters or bytes, they return the number of characters or bytes in the string. If number is less than zero, they return 0. In previous versions, these functions had a return value of type int rather than size_t.

_strncnt returns the number of characters in the first number bytes of the single-byte string string. _wcsncnt returns the number of bytes in the first number wide characters of the wide-character string string.

Parameters

string

String to be examined

number

Number of characters or bytes to be examined in string

Remarks

_mbsnbcnt counts the number of bytes found in the first number of multibyte characters of string. _mbsnbcnt replaces mtob, and should be used in place of mtob.

_mbsnccnt counts the number of characters found in the first number of bytes of string. If _mbsnccnt encounters a NULL in the second byte of a double-byte character, the first byte is also considered to be NULL and is not included in the returned count value. _mbsnccnt replaces btom, and should be used in place of btom.

If _MBCS is defined, _mbsnbcnt is mapped to _tcsnbcnt and _mbsnbcnt is mapped to _tcsnccnt. These two mapping routines provide generic-text support and are defined in TCHAR.H. If _UNICODE is defined, both _mbsnbcnt and _mbsnccnt are mapped to the _wcsncnt macro. When _MBCS and _UNICODE are not defined, both _tcsnbcnt and _tcsnccnt are mapped to the _strncnt macro. _strncnt is the single-byte–character string version and _wcsncnt is the wide-character–string version of these mapping routines. _strncnt and _wcsncnt are provided only for generic-text mapping and should not be used otherwise. For more information, see Using Generic-Text Mappings and see Appendix B, Generic-Text Mappings.

Example

/* MBSNBCNT.C */

#include  <mbstring.h>
#include  <stdio.h>

void main( void )
{
   unsigned char str[] = "This is a multibyte-character string.";
   unsigned int char_count, byte_count;
   char_count = _mbsnccnt( str, 10 );
   byte_count = _mbsnbcnt( str, 10 );
   if ( byte_count - char_count )
      printf( "The first 10 characters contain %s multibyte characters", char_count );
   else
      printf( "The first 10 characters are single-byte.");
}

Output

The first 10 characters are single-byte.

String Manipulation Routines

See Also _mbsnbcat


_mbsnbcoll, _mbsnbicoll

int _mbsnbcoll( const unsigned char *string1, const unsigned char string2, size_t count );

int _mbsnbicoll( const unsigned char *string1, const unsigned char string2, size_t count );

Routine | Required Header | Compatibility
_mbsnbcoll | <mbstring.h> | Win 95, Win NT
_mbsnbicoll | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relation of the substrings of string1 and string2.

Return Value | Description
< 0 | string1 substring less than string2 substring
0 | string1 substring identical to string2 substring
> 0 | string1 substring greater than string2 substring

Each of these functions returns _NLSCMPERROR on an error. To use _NLSCMPERROR, include either STRING.H or MBSTRING.H.

Parameters

string1, string2

Strings to compare

count

Number of bytes to compare

Remarks

Each of these functions collates, at most, the first count bytes in string1 and string2 and returns a value indicating the relationship between the resulting substrings of string1 and string2. If the final byte in the substring of string1 or string2 is a lead byte, it is not included in the comparison; these functions compare only complete characters in the substrings. _mbsnbicoll is a case-insensitive version of _mbsnbcoll. Like _mbsnbcmp and _mbsnbicmp, _mbsnbcoll and _mbsnbicoll collate the two multibyte-character strings according to the lexicographic order specified by the multibyte code page currently in use.

For some code pages and corresponding character sets, the order of characters in the character set may differ from the lexicographic character order. In the “C” locale, this is not the case: the order of characters in the ASCII character set is the same as the lexicographic order of the characters. However, in certain European code pages, for example, the character 'a' (value 0x61) precedes the character 'ä' (value 0xE4) in the character set, but the character 'ä' precedes the character 'a' lexicographically. To perform a lexicographic comparison of strings by bytes in such an instance, use _mbsnbcoll rather than _mbsnbcmp; to check only for string equality, use _mbsnbcmp.

Because the coll functions collate strings lexicographically for comparison, whereas the cmp functions simply test for string equality, the coll functions are much slower than the corresponding cmp versions. Therefore, the coll functions should be used only when there is a difference between the character set order and the lexicographic character order in the current code page and this difference is of interest for the comparison.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncoll | _strncoll | _mbsnbcoll | _wcsncoll
_tcsnicoll | _strnicoll | _mbsnbicoll | _wcsnicoll

String Manipulation Routines

See Also _mbsnbcat, _mbsnbcmp, _mbsnbicmp, strcoll Functions, strncmp, _strnicmp


_mbsnbcpy

unsigned char * _mbsnbcpy( unsigned char *dest, const unsigned char *src, size_t count );

Routine | Required Header | Compatibility
_mbsnbcpy | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbsnbcpy returns a pointer to the character string that is to be copied.

Parameters

dest

Destination for character string to be copied

src

Character string to be copied

count

Number of bytes to be copied

Remarks

The _mbsnbcpy function copies count bytes from src to dest. If src is shorter than dest, the string is padded with null characters. If dest is less than or equal to count it is not terminated with a null character.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncpy | strncpy | _mbsnbcpy | wcsncpy

String Manipulation Routines

See Also _mbsnbcat, _mbsnbcmp, _mbsnbcnt, _mbsnccnt, _mbsnbicmp, _mbsnbset, _mbsncpy


_mbsnbicmp

int _mbsnbicmp( const unsigned char *string1, const unsigned char *string2, size_t count );

Routine | Required Header | Compatibility
_mbsnbicmp | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relationship between the substrings.

Return Value | Description
< 0 | string1 substring less than string2 substring
0 | string1 substring identical to string2 substring
> 0 | string1 substring greater than string2 substring

On an error, _mbsnbcmp returns _NLSCMPERROR, which is defined in STRING.H and MBSTRING.H.

Parameters

string1, string2

Null-terminated strings to compare

count

Number of bytes to compare

Remarks

The _mbsnbicmp function lexicographically compares, at most, the first count bytes of string1 and string2. The comparison is performed without regard to case; _mbsnbcmp is a case-sensitive version of _mbsnbicmp. The comparison ends if a terminating null character is reached in either string before count characters are compared. If the strings are equal when a terminating null character is reached in either string before count characters are compared, the shorter string is lesser.

_mbsnbicmp is similar to _mbsnicmp, except that it compares strings by bytes instead of by characters.

Two strings containing characters located between 'Z' and 'a' in the ASCII table ('[', '\', ']', '^', '_', and '`') compare differently, depending on their case. For example, the two strings "ABCDE" and "ABCD^" compare one way if the comparison is lowercase ("abcde" > "abcd^") and the other way ("ABCDE" < "ABCD^") if it is uppercase.

_mbsnbicmp recognizes multibyte-character sequences according to the multibyte code page currently in use. It is not affected by the current locale setting.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsnicmp | _strnicmp | _mbsnbicmp | _wcsnicmp

Example

/* STRNBCMP.C */
#include <mbstring.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown fox jumps over the lazy dog";

void main( void )
{
   char tmp[20];
   int result;
   printf( "Compare strings:\n\t\t%s\n\t\t%s\n\n", string1, string2 );
   printf( "Function:\t_mbsnbcmp (first 10 characters only)\n" );
   result = _mbsncmp( string1, string2 , 10 );
   if( result > 0 )
      _mbscpy( tmp, "greater than" );
   else if( result < 0 )
      _mbscpy( tmp, "less than" );
   else
      _mbscpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
   printf( "Function:\t_mbsnicmp _mbsnicmp (first 10 characters only)\n" );
   result = _mbsnicmp( string1, string2, 10 );
   if( result > 0 )
      _mbscpy( tmp, "greater than" );
   else if( result < 0 )
      _mbscpy( tmp, "less than" );
   else
      _mbscpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
}

Output

Compare strings:
      The quick brown dog jumps over the lazy fox
      The QUICK brown fox jumps over the lazy dog

Function:   _mbsnbcmp (first 10 characters only)
Result:      String 1 is greater than string 2

Function:   _mbsnicmp (first 10 characters only)
Result:      String 1 is equal to string 2

String Manipulation Routines

See Also _mbsnbcat, _mbsnbcmp, _stricmp


_mbsnbset

unsigned char *_mbsnbset( unsigned char *string, unsigned int c, size_t count );

Routine | Required Header | Compatibility
_mbsnbset | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_mbsnbset returns a pointer to the altered string.

Parameters

string

String to be altered

c

Single-byte or multibyte character setting

count

Number of bytes to be set

Remarks

The _mbsnbset function sets, at most, the first count bytes of string to c. If count is greater than the length of string, the length of string is used instead of count. If c is a multibyte character and cannot be set entirely into the last byte specified by count, then the last byte will be padded with a blank character. _mbsnbset does not place a terminating null at the end of string.

_mbsnbset is similar to _mbsnset, except that it sets count bytes rather than count characters of c.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsnset | _strnset | _mbsnbset | _wcsnset

Example

/* MBSNBSET.C */

#include <mbstring.h>
#include <stdio.h>

void main( void )
{
   char string[15] = "This is a test";
   /* Set not more than 4 bytes of string to be *'s */
   printf( "Before: %s\n", string );
   _mbsnbset( string, '*', 4 );
   printf( "After:  %s\n", string );
}

Output

Before: This is a test
After:  **** is a test

String Manipulation Routines

See Also _mbsnbcat, _mbsnset, _mbsset


_mbsnextc, _strnextc, _wcsnextc

unsigned int _mbsnextc( const unsigned char *string );

Routine | Required Header | Compatibility
_mbsnextc | <mbstring.h> | Win 95, Win NT
_strnextc | <tchar.h> | Win 95, Win NT
_wcsnextc | <tchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the integer value of the next character in string.

Parameter

string

Source string

Remarks

The _mbsnextc function returns the integer value of the next multibyte-character in string, without advancing the string pointer. _mbsnextc recognizes multibyte-character sequences according to the multibyte code page currently in use.

The generic-text function _tcsnextc, defined in TCHAR.H, maps to _mbsnextc if _MBCS has been defined, or to _wcsnextc if _UNICODE has been defined. Otherwise _tcsnextc maps to _strnextc. _strnextc and _wcsnextc are single-byte–character string and wide-character string versions of _mbsnextc. _wcsnextc returns the integer value of the next wide character in string; _strnextc returns the integer value of the next single-byte character in string. _strnextc and _wcsnextc are provided only for this mapping and should not be used otherwise. For more information, see Using Generic-Text Mappings and Appendix B, Generic-Text Mappings.

String Manipulation Routines

See Also _mbsdec, _mbsinc, _mbsninc


_mbsninc, _strninc, _wcsninc

unsigned char *_mbsninc( const unsigned char *string, size_t count );

Routine | Required Header | Compatibility
_mbsninc | <mbstring.h> | Win 95, Win NT
_strninc | <tchar.h> | Win 95, Win NT
_wcsninc | <tchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines returns a pointer to string after string has been incremented by count characters, or NULL if the supplied pointer is NULL. If count is greater than or equal to the number of characters in string, the result is undefined.

Parameters

string

Source string

count

Number of characters to increment string pointer

Remarks

The _mbsninc function increments string by count multibyte characters. _mbsninc recognizes multibyte-character sequences according to the multibyte code page currently in use.

The generic-text function _tcsninc, defined in TCHAR.H, maps to _mbsninc if _MBCS has been defined, or to _wcsninc if _UNICODE has been defined. Otherwise _tcsninc maps to _strninc. _strninc and _wcsninc are single-byte–character string and wide-character string versions of _mbsninc. _wcsninc and _strninc are provided only for this mapping and should not be used otherwise. For more information, see Using Generic-Text Mappings and Appendix B, Generic-Text Mappings.

String Manipulation Routines

See Also _mbsdec, _mbsinc, _mbsnextc


_mbsspnp, _strspnp, _wcsspnp

unsigned char *_mbsspnp( const unsigned char *string1,
const unsigned char *string2 );

Routine | Required Header | Compatibility
_mbsspnp | <mbstring.h> | Win 95, Win NT
_strspnp | <tchar.h> | Win 95, Win NT
_wcsspnp | <tchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_strspnp, _wcsspnp, and _mbsspnp return a pointer to the first character in string1 that does not belong to the set of characters in string2. Each of these functions returns NULL if string1 consists entirely of characters from string2. For each of these routines, no return value is reserved to indicate an error.

Parameters

string1

Null-terminated string to search

string2

Null-terminated character set

Remarks

The _mbsspnp function returns a pointer to the multibyte character that is the first character in string1 that does not belong to the set of characters in string2. _mbsspnp recognizes multibyte-character sequences according to the multibyte code page currently in use. The search does not include terminating null characters.

The generic-text function _tcsspnp, defined in TCHAR.H, maps to _mbsspnp if _MBCS has been defined, or to _wcsspnp if _UNICODE has been defined. Otherwise _tcsspnp maps to _strspnp. _strspnp and _wcsspnp are single-byte character and wide-character versions of _mbsspnp. _strspnp and _wcsspnp behave identically to _mbsspnp otherwise; they are provided only for this mapping and should not be used for any other reason. For more information, see Using Generic-Text Mappings and Appendix B, Generic-Text Mappings.

Example

/* STRSPN.C: This program uses strspn to determine
 * the length of the segment in the string "cabbage"
 * consisting of a's, b's, and c's. In other words,
 * it finds the first non-abc letter.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[] = "cabbage";
   int  result;
   result = strspn( string, "abc" );
   printf( "The portion of '%s' containing only a, b, or c "
           "is %d bytes long\n", string, result );
}

Output

The portion of 'cabbage' containing only a, b, or c is 5 bytes long

String Manipulation Routines

See Also strspn, strcspn, strncat, strncmp, strncpy, _strnicmp, strrchr


mbstowcs

Converts a sequence of multibyte characters to a corresponding sequence of wide characters.

size_t mbstowcs( wchar_t *wcstr, const char *mbstr, size_t count );

Routine | Required Header | Compatibility
mbstowcs | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If mbstowcs successfully converts the source string, it returns the number of converted multibyte characters. If the wcstr argument is NULL, the function returns the required size of the destination string. If mbstowcs encounters an invalid multibyte character, it returns –1. If the return value is count, the wide-character string is not null-terminated.

Parameters

wcstr

The address of a sequence of wide characters

mbstr

The address of a sequence of multibyte characters

count

The number of multibyte characters to convert

Remarks

The mbstowcs function converts count or fewer multibyte characters pointed to by mbstr to a string of corresponding wide characters that are determined by the current locale. It stores the resulting wide-character string at the address represented by wcstr. The result is similiar to a series of calls to mbtowc. If mbstowcs encounters the single-byte null character ('\0') either before or when count occurs, it converts the null character to a wide-character null character (L'\0') and stops. Thus the wide-character string at wcstr is null-terminated only if a null character is encountered during conversion. If the sequences pointed to by wcstr and mbstr overlap, the behavior is undefined.

If the wcstr argument is NULL, mbstowcs returns the required size of the destination string.

Example

/* MBSTOWCS.CPP illustrates the behavior of the mbstowcs function
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
    int i;
    char    *pmbnull  = NULL;
    char    *pmbhello = (char *)malloc( MB_CUR_MAX );
    wchar_t *pwchello = L"Hi";
    wchar_t *pwc      = (wchar_t *)malloc( sizeof( wchar_t ));

    printf( "Convert to multibyte string:\n" );
    i = wcstombs( pmbhello, pwchello, MB_CUR_MAX );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tHex value of first" );
    printf( " multibyte character: %#.4x\n\n", pmbhello );

    printf( "Convert back to wide-character string:\n" );
    i = mbstowcs( pwc, pmbhello, MB_CUR_MAX );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tHex value of first" );
    printf( " wide character: %#.4x\n\n", pwc );
}

Output

Convert to multibyte string:
   Characters converted: 1
   Hex value of first multibyte character: 0x0e1a

Convert back to wide-character string:
   Characters converted: 1
   Hex value of first wide character: 0x0e1e

Data Conversion Routines | Locale Routines | Interpretation of Multibyte-Character Sequences

See Also mblen, mbtowc, wcstombs, wctomb, MultiByteToWideChar


mbtowc

Convert a multibyte character to a corresponding wide character.

int mbtowc( wchar_t *wchar, const char *mbchar, size_t count );

Routine | Required Header | Compatibility
mbtowc | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If mbchar is not NULL and if the object that mbchar points to forms a valid multibyte character, mbtowc returns the length in bytes of the multibyte character. If mbchar is NULL or the object that it points to is a wide-character null character (L'\0'), the function returns 0. If the object that mbchar points to does not form a valid multibyte character within the first count characters, it returns –1.

Parameters

wchar

Address of a wide character (type wchar_t)

mbchar

Address of a sequence of bytes (a multibyte character)

count

Number of bytes to check

Remarks

The mbtowc function converts count or fewer bytes pointed to by mbchar, if mbchar is not NULL, to a corresponding wide character. mbtowc stores the resulting wide character at wchar, if wchar is not NULL. mbtowc does not examine more than MB_CUR_MAX bytes.

Example

/* MBTOWC.CPP illustrates the behavior of the mbtowc function
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
    int      i;
    char    *pmbc    = (char *)malloc( sizeof( char ) );
    wchar_t  wc      = L'a';
    wchar_t *pwcnull = NULL;
    wchar_t *pwc     = (wchar_t *)malloc( sizeof( wchar_t ) );
    printf( "Convert a wide character to multibyte character:\n" );
    i = wctomb( pmbc, wc );
    printf( "\tCharacters converted: %u\n", i );
    printf( "\tMultibyte character: %x\n\n", pmbc );

    printf( "Convert multibyte character back to a wide "
            "character:\n" );
    i = mbtowc( pwc, pmbc, MB_CUR_MAX );
    printf( "\tBytes converted: %u\n", i );
    printf( "\tWide character: %x\n\n", pwc );
    printf( "Attempt to convert when target is NULL\n" );
    printf( "  returns the length of the multibyte character:\n" );
    i = mbtowc( pwcnull, pmbc, MB_CUR_MAX );
    printf( "\tLength of multibyte character: %u\n\n", i );

    printf( "Attempt to convert a NULL pointer to a" );
    printf( " wide character:\n" );
    pmbc = NULL;
    i = mbtowc( pwc, pmbc, MB_CUR_MAX );
    printf( "\tBytes converted: %u\n", i );
}

Output

Convert a wide character to multibyte character:
   Characters converted: 1
   Multibyte character: 2d02d4

Convert multibyte character back to a wide character:
   Bytes converted: 1
   Wide character: 2d02dc

Attempt to convert when target is NULL
  returns the length of the multibyte character:
   Length of multibyte character: 1

Attempt to convert a NULL pointer to a wide character:
   Bytes converted: 0

Data Conversion Routines | Locale Routines | Interpretation of Multibyte-Character Sequences

See Also mblen, wcstombs, wctomb, MultiByteToWideChar


_memccpy

Copies characters from a buffer.

void *_memccpy( void *dest, const void *src, int c, unsigned int count );

Routine | Required Header | Compatibility
_memccpy | <memory.h> or <string.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If the character c is copied, _memccpy returns a pointer to the byte in dest that immediately follows the character. If c is not copied, it returns NULL.

Parameters

dest

Pointer to destination

src

Pointer to source

c

Last character to copy

count

Number of characters

Remarks

The _memccpy function copies 0 or more bytes of src to dest, halting when the character c has been copied or when count bytes have been copied, whichever comes first.

Example

/* MEMCCPY.C */

#include <memory.h>
#include <stdio.h>
#include <string.h>

char string1[60] = "The quick brown dog jumps over the lazy fox";

void main( void )
{
   char buffer[61];
   char *pdest;

   printf( "Function:\t_memccpy 60 characters or to character 's'\n" );
   printf( "Source:\t\t%s\n", string1 );
   pdest = _memccpy( buffer, string1, 's', 60 );
   *pdest = '\0';
   printf( "Result:\t\t%s\n", buffer );
   printf( "Length:\t\t%d characters\n\n", strlen( buffer ) );
}

Output

Function:   _memccpy 60 characters or to character 's'
Source:      The quick brown dog jumps over the lazy fox
Result:      The quick brown dog jumps
Length:      25 characters

Buffer Manipulation Routines

See Also memchr, memcmp, memcpy, memset


memchr

Finds characters in a buffer.

void *memchr( const void *buf, int c, size_t count );

Routine | Required Header | Compatibility
memchr | <memory.h> or <string.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, memchr returns a pointer to the first location of c in buf. Otherwise it returns NULL.

Parameters

buf

Pointer to buffer

c

Character to look for

count

Number of characters to check

Remarks

The memchr function looks for the first occurrence of c in the first count bytes of buf. It stops when it finds c or when it has checked the first count bytes.

Example

/* MEMCHR.C */

#include <memory.h>
#include <stdio.h>

int  ch = 'r';
char str[] =    "lazy";
char string[] = "The quick brown dog jumps over the lazy fox";
char fmt1[] =   "         1         2         3         4         5";
char fmt2[] =   "12345678901234567890123456789012345678901234567890";

void main( void )
{
   char *pdest;
   int result;
   printf( "String to be searched:\n\t\t%s\n", string );
   printf( "\t\t%s\n\t\t%s\n\n", fmt1, fmt2 );

   printf( "Search char:\t%c\n", ch );
   pdest = memchr( string, ch, sizeof( string ) );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\t\t%c found at position %d\n\n", ch, result );
   else
      printf( "Result:\t\t%c not found\n" );
}

Output

String to be searched:
      The quick brown dog jumps over the lazy fox
               1         2         3         4         5
      12345678901234567890123456789012345678901234567890

Search char:   r
Result:      r found at position 12

Buffer Manipulation Routines

See Also _memccpy, memcmp, memcpy, memset, strchr


memcmp

Compare characters in two buffers.

int memcmp( const void *buf1, const void *buf2, size_t count );

Routine | Required Header | Compatibility
memcmp | <memory.h> or <string.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relationship between the buffers.

Return Value | Relationship of First count Bytes of buf1 and buf2
< 0 | buf1 less than buf2
0 | buf1 identical to buf2
> 0 | buf1 greater than buf2

Parameters

buf1

First buffer

buf2

Second buffer

count

Number of characters

Remarks

The memcmp function compares the first count bytes of buf1 and buf2 and returns a value indicating their relationship.

Example

/* MEMCMP.C: This program uses memcmp to compare
 * the strings named first and second. If the first
 * 19 bytes of the strings are equal, the program
 * considers the strings to be equal.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char first[]  = "12345678901234567890";
   char second[] = "12345678901234567891";
   int result;

   printf( "Compare '%.19s' to '%.19s':\n", first, second );
   result = memcmp( first, second, 19 );
   if( result < 0 )
      printf( "First is less than second.\n" );
   else if( result == 0 )
      printf( "First is equal to second.\n" );
   else if( result > 0 )
      printf( "First is greater than second.\n" );
   printf( "Compare '%.20s' to '%.20s':\n", first, second );
   result = memcmp( first, second, 20 );
   if( result < 0 )
      printf( "First is less than second.\n" );
   else if( result == 0 )
      printf( "First is equal to second.\n" );
   else if( result > 0 )
      printf( "First is greater than second.\n" );
}

Output

Compare '1234567890123456789' to '1234567890123456789':
First is equal to second.
Compare '12345678901234567890' to '12345678901234567891':
First is less than second.

Buffer Manipulation Routines

See Also _memccpy, memchr, memcpy, memset, strcmp, strncmp


memcpy

Copies characters between buffers.

void *memcpy( void *dest, const void *src, size_t count );

Routine | Required Header | Compatibility
memcpy | <memory.h> or <string.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

memcpy returns the value of dest.

Parameters

dest

New buffer

src

Buffer to copy from

count

Number of characters to copy

Remarks

The memcpy function copies count bytes of src to dest. If the source and destination overlap, this function does not ensure that the original source bytes in the overlapping region are copied before being overwritten. Use memmove to handle overlapping regions.

Example

/* MEMCPY.C: Illustrate overlapping copy: memmove
 * handles it correctly; memcpy does not.
 */

#include <memory.h>
#include <string.h>
#include <stdio.h>

char string1[60] = "The quick brown dog jumps over the lazy fox";
char string2[60] = "The quick brown fox jumps over the lazy dog";
/*                           1         2         3         4         5
 *                  12345678901234567890123456789012345678901234567890
 */

void main( void )
{
   printf( "Function:\tmemcpy without overlap\n" );
   printf( "Source:\t\t%s\n", string1 + 40 );
   printf( "Destination:\t%s\n", string1 + 16 );
   memcpy( string1 + 16, string1 + 40, 3 );
   printf( "Result:\t\t%s\n", string1 );
   printf( "Length:\t\t%d characters\n\n", strlen( string1 ) );

   /* Restore string1 to original contents */
   memcpy( string1 + 16, string2 + 40, 3 );

   printf( "Function:\tmemmove with overlap\n" );
   printf( "Source:\t\t%s\n", string2 + 4 );
   printf( "Destination:\t%s\n", string2 + 10 );
   memmove( string2 + 10, string2 + 4, 40 );
   printf( "Result:\t\t%s\n", string2 );
   printf( "Length:\t\t%d characters\n\n", strlen( string2 ) );

   printf( "Function:\tmemcpy with overlap\n" );
   printf( "Source:\t\t%s\n", string1 + 4 );
   printf( "Destination:\t%s\n", string1 + 10 );
   memcpy( string1 + 10, string1 + 4, 40 );
   printf( "Result:\t\t%s\n", string1 );
   printf( "Length:\t\t%d characters\n\n", strlen( string1 ) );
}

Output

Function:   memcpy without overlap
Source:      fox
Destination:   dog jumps over the lazy fox
Result:      The quick brown fox jumps over the lazy fox
Length:      43 characters

Function:   memmove with overlap
Source:      quick brown fox jumps over the lazy dog
Destination:   brown fox jumps over the lazy dog
Result:      The quick quick brown fox jumps over the lazy dog
Length:      49 characters

Function:   memcpy with overlap
Source:      quick brown dog jumps over the lazy fox
Destination:   brown dog jumps over the lazy fox
Result:      The quick quick brown dog jumps over the lazy fox
Length:      49 characters

Buffer Manipulation Routines

See Also _memccpy, memchr, memcmp, memmove, memset, strcpy, strncpy


_memicmp

Compares characters in two buffers (case-insensitive).

int _memicmp( const void *buf1, const void *buf2, unsigned int count );

Routine | Required Header | Compatibility
_memicmp | <memory.h> or <string.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relationship between the buffers.

Return Value | Relationship of First count Bytes of buf1 and buf2
< 0 | buf1 less than buf2
0 | buf1 identical to buf2
> 0 | buf1 greater than buf2

Parameters

buf1

First buffer

buf2

Second buffer

count

Number of characters

Remarks

The _memicmp function compares the first count characters of the two buffers buf1 and buf2 byte by byte. The comparison is not case sensitive.

Example

/* MEMICMP.C: This program uses _memicmp to compare
 * the first 29 letters of the strings named first and
 * second without regard to the case of the letters.
 */

#include <memory.h>
#include <stdio.h>
#include <string.h>

void main( void )
{
   int result;
   char first[] = "Those Who Will Not Learn from History";
   char second[] = "THOSE WHO WILL NOT LEARN FROM their mistakes";
   /* Note that the 29th character is right here ^ */

   printf( "Compare '%.29s' to '%.29s'\n", first, second );
   result = _memicmp( first, second, 29 );
   if( result < 0 )
      printf( "First is less than second.\n" );
   else if( result == 0 )
      printf( "First is equal to second.\n" );}
   else if( result > 0 )
      printf( "First is greater than second.\n" );
}

Output

Compare 'Those Who Will Not Learn from' to 'THOSE WHO WILL NOT LEARN FROM'
First is equal to second.

Buffer Manipulation Routines

See Also _memccpy, memchr, memcmp, memcpy, memset, _stricmp, _strnicmp


memmove

Moves one buffer to another.

void *memmove( void *dest, const void *src, size_t count );

Routine | Required Header | Compatibility
memmove | <string.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

memmove returns the value of dest.

Parameters

dest

Destination object

src

Source object

count

Number of bytes of characters to copy

Remarks

The memmove function copies count bytes of characters from src to dest. If some regions of the source area and the destination overlap, memmove ensures that the original source bytes in the overlapping region are copied before being overwritten.

Example

/* MEMCPY.C: Illustrate overlapping copy: memmove
 * handles it correctly; memcpy does not.
 */

#include <memory.h>
#include <string.h>
#include <stdio.h>

char string1[60] = "The quick brown dog jumps over the lazy fox";
char string2[60] = "The quick brown fox jumps over the lazy dog";
/*                           1         2         3         4         5
 *                  12345678901234567890123456789012345678901234567890
 */

void main( void )
{
   printf( "Function:\tmemcpy without overlap\n" );
   printf( "Source:\t\t%s\n", string1 + 40 );
   printf( "Destination:\t%s\n", string1 + 16 );
   memcpy( string1 + 16, string1 + 40, 3 );
   printf( "Result:\t\t%s\n", string1 );
   printf( "Length:\t\t%d characters\n\n", strlen( string1 ) );

   /* Restore string1 to original contents */
   memcpy( string1 + 16, string2 + 40, 3 );

   printf( "Function:\tmemmove with overlap\n" );
   printf( "Source:\t\t%s\n", string2 + 4 );
   printf( "Destination:\t%s\n", string2 + 10 );
   memmove( string2 + 10, string2 + 4, 40 );
   printf( "Result:\t\t%s\n", string2 );
   printf( "Length:\t\t%d characters\n\n", strlen( string2 ) );

   printf( "Function:\tmemcpy with overlap\n" );
   printf( "Source:\t\t%s\n", string1 + 4 );
   printf( "Destination:\t%s\n", string1 + 10 );
   memcpy( string1 + 10, string1 + 4, 40 );
   printf( "Result:\t\t%s\n", string1 );
   printf( "Length:\t\t%d characters\n\n", strlen( string1 ) );
}

Output

Function:   memcpy without overlap
Source:      fox
Destination:   dog jumps over the lazy fox
Result:      The quick brown fox jumps over the lazy fox
Length:      43 characters

Function:   memmove with overlap
Source:      quick brown fox jumps over the lazy dog
Destination:   brown fox jumps over the lazy dog
Result:      The quick quick brown fox jumps over the lazy dog
Length:      49 characters

Function:   memcpy with overlap
Source:      quick brown dog jumps over the lazy fox
Destination:   brown dog jumps over the lazy fox
Result:      The quick quick brown dog jumps over the lazy fox
Length:      49 characters

Buffer Manipulation Routines

See Also _memccpy, memcpy, strcpy, strncpy


memset

Sets buffers to a specified character.

void *memset( void *dest, int c, size_t count );

Routine | Required Header | Compatibility
memset | <memory.h> or <string.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

memset returns the value of dest.

Parameters

dest

Pointer to destination

c

Character to set

count

Number of characters

Remarks

The memset function sets the first count bytes of dest to the character c.

Example

/* MEMSET.C: This program uses memset to
 * set the first four bytes of buffer to "*".
 */

#include <memory.h>
#include <stdio.h>

void main( void )
{
   char buffer[] = "This is a test of the memset function";

   printf( "Before: %s\n", buffer );
   memset( buffer, '*', 4 );
   printf( "After:  %s\n", buffer );
}

Output

Before: This is a test of the memset function
After:  **** is a test of the memset function

Buffer Manipulation Routines

See Also _memccpy, memchr, memcmp, memcpy, _strnset


__min

Returns the smaller of two values.

type __min( type a, type b );

Routine | Required Header | Compatibility
__min | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The smaller of the two arguments

Parameters

type

Any numeric data type

a, b

Values of any numeric type to be compared

Remarks

The __min macro compares two values and returns the value of the smaller one. The arguments can be of any numeric data type, signed or unsigned. Both arguments and the return value must be of the same data type.

Example

/* MINMAX.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   int a = 10;
   int b = 21;

   printf( "The larger of %d and %d is %d\n",  a, b, __max( a, b ) );
   printf( "The smaller of %d and %d is %d\n", a, b, __min( a, b ) );
}

Output

The larger of 10 and 21 is 21
The smaller of 10 and 21 is 10

Floating-Point Support Routines

See Also __max


_mkdir, _wmkdir

Create a new directory.

int _mkdir( const char *dirname );

int _wmkdir( const wchar_t *dirname );

Routine | Required Header | Compatibility
_mkdir | <direct.h> | Win 95, Win NT
_wmkdir | <direct.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the value 0 if the new directory was created. On an error the function returns –1 and sets errno as follows:

EEXIST

Directory was not created because dirname is the name of an existing file, directory, or device

ENOENT

Path was not found

Parameter

dirname

Path for new directory

Remarks

The _mkdir function creates a new directory with the specified dirname. _mkdir can create only one new directory per call, so only the last component of dirname can name a new directory. _mkdir does not translate path delimiters. In Windows NT, both the backslash ( \) and the forward slash (/ ) are valid path delimiters in character strings in run-time routines.

_wmkdir is a wide-character version of _mkdir; the dirname argument to _wmkdir is a wide-character string. _wmkdir and _mkdir behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tmkdir | _mkdir | _mkdir | _wmkdir

Example

/* MAKEDIR.C */

#include <direct.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   if( _mkdir( "\\testtmp" ) == 0 )
   {
      printf( "Directory '\\testtmp' was successfully created\n" );
      system( "dir \\testtmp" );
      if( _rmdir( "\\testtmp" ) == 0 )
        printf( "Directory '\\testtmp' was successfully removed\n"  );
      else
         printf( "Problem removing directory '\\testtmp'\n" );
   }
   else
      printf( "Problem creating directory '\\testtmp'\n" );
}

Output

Directory '\testtmp' was successfully created
 Volume in drive C is CDRIVE
 Volume Serial Number is 0E17-1702

 Directory of C:\testtmp

05/03/94  12:30p        <DIR>           .
05/03/94  12:30p        <DIR>           ..
               2 File(s)          0 bytes
                             17,358,848 bytes free
Directory '\testtmp' was successfully removed

Directory Control Routines

See Also _chdir, _rmdir


_mktemp, _wmktemp

Create a unique filename.

char *_mktemp( char *template );

wchar_t *_wmktemp( wchar_t *template );

Routine | Required Header | Compatibility
_mktemp | <io.h> | Win 95, Win NTv
_wmktemp | <io.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the modified template. The function returns NULL if template is badly formed or no more unique names can be created from the given template.

Parameter

template

Filename pattern

Remarks

The _mktemp function creates a unique filename by modifying the template argument. _mktemp automatically handles multibyte-character string arguments as appropriate, recognizing multibyte-character sequences according to the multibyte code page currently in use by the run-time system. _wmktemp is a wide-character version of _mktemp; the argument and return value of _wmktemp are wide-character strings. _wmktemp and _mktemp behave identically otherwise, except that _wmktemp does not handle multibyte-character strings.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tmktemp | _mktemp | _mktemp | _wmktemp

The template argument has the form baseXXXXXX where base is the part of the new filename that you supply and each X is a placeholder for a character supplied by _mktemp. Each placeholder character in template must be an uppercase X. _mktemp preserves base and replaces the first trailing X with an alphabetic character. _mktemp replaces the following trailing X's with a five-digit value; this value is a unique number identifying the calling process, or in multi-threaded programs, the calling thread.

Each successful call to _mktemp modifies template. In each subsequent call from the same process or thread with the same template argument, _mktemp checks for filenames that match names returned by _mktemp in previous calls. If no file exists for a given name, _mktemp returns that name. If files exist for all previously returned names, _mktemp creates a new name by replacing the alphabetic character it used in the previously returned name with the next available lowercase letter, in order, from 'a' through 'z'. For example, if base is

fn

and the five-digit value supplied by _mktemp is 12345, the first name returned is

fna12345

If this name is used to create file FNA12345 and this file still exists, the next name returned on a call from the same process or thread with the same base for template will be

fnb12345

If FNA12345 does not exist, the next name returned will again be

fna12345

_mktemp can create a maximum of 27 unique filenames for any given combination of base and template values. Therefore, FNZ12345 is the last unique filename _mktemp can create for the base and template values used in this example.

Example

/* MKTEMP.C: The program uses _mktemp to create
 * five unique filenames. It opens each filename
 * to ensure that the next name is unique.
 */

#include <io.h>
#include <string.h>
#include <stdio.h>

char *template = "fnXXXXXX";
char *result;
char names[5][9];

void main( void )
{
   int i;
   FILE *fp;

   for( i = 0; i < 5; i++ )
   {
      strcpy( names[i], template );
      /* Attempt to find a unique filename: */
      result = _mktemp( names[i] );
      if( result == NULL )
         printf( "Problem creating the template" );
      else
      {
         if( (fp = fopen( result, "w" )) != NULL )
            printf( "Unique filename is %s\n", result );
         else
            printf( "Cannot open %s\n", result );
         fclose( fp );
      }
   }
}

Output

Unique filename is fna00141
Unique filename is fnb00141
Unique filename is fnc00141
Unique filename is fnd00141
Unique filename is fne00141

File Handling Routines

See Also fopen, _getmbcp, _getpid, _open, _setmbcp, _tempnam, tmpfile


mktime

Converts the local time to a calendar value.

time_t mktime( struct tm *timeptr );

Routine | Required Header | Compatibility
mktime | <time.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

mktime returns the specified calendar time encoded as a value of type time_t. If timeptr references a date before midnight, January 1, 1970, or if the calendar time cannot be represented, the function returns –1 cast to type time_t.

Parameter

timeptr

Pointer to time structure

Remarks

The mktime function converts the supplied time structure (possibly incomplete) pointed to by timeptr into a fully defined structure with normalized values and then converts it to a time_t calendar time value. For description of tm structure fields, see asctime. The converted time has the same encoding as the values returned by the time function. The original values of the tm_wday and tm_yday components of the timeptr structure are ignored, and the original values of the other components are not restricted to their normal ranges.

mktime handles dates in any time zone from midnight, January 1, 1970, to January 18, 19:14:07, 2038. If successful, mktime sets the values of tm_wday and tm_yday as appropriate and sets the other components to represent the specified calendar time, but with their values forced to the normal ranges; the final value of tm_mday is not set until tm_mon and tm_year are determined. When specifying a tm structure time, set the tm_isdst field to 0 to indicate that standard time is in effect, or to a value greater than 0 to indicate that daylight savings time is in effect, or to a value less than zero to have the C run-time library code compute whether standard time or daylight savings time is in effect. (The C run-time library assumes the United States’s rules for implementing the calculation of Daylight Saving Time). tm_isdst is a required field. If not set, its value is undefined and the return value from mktime is unpredictable. If timeptr points to a tm structure returned by a previous call to asctime, gmtime, or localtime, the tm_isdst field contains the correct value.

Note that gmtime and localtime use a single statically allocated buffer for the conversion. If you supply this buffer to mktime, the previous contents are destroyed.

Example

/* MKTIME.C: The example takes a number of days
 * as input and returns the time, the current
 * date, and the specified number of days.
 */

#include <time.h>
#include <stdio.h>

void main( void )
{
   struct tm when;
   time_t now, result;
   int    days;

   time( &now );
   when = *localtime( &now );
   printf( "Current time is %s\n", asctime( &when ) );
   printf( "How many days to look ahead: " );
   scanf( "%d", &days );

   when.tm_mday = when.tm_mday + days;
   if( (result = mktime( &when )) != (time_t)-1 )
      printf( "In %d days the time will be %s\n",
              days, asctime( &when ) );
   else
      perror( "mktime failed" );
}

Output

Current time is Tue May 03 12:45:47 1994

How many days to look ahead: 29
In 29 days the time will be Wed Jun 01 12:45:47 1994

Time Management Routines

See Also asctime, gmtime, localtime, time


modf

Splits a floating-point value into fractional and integer parts.

double modf( double x, double *intptr );

Routine | Required Header | Compatibility
modf | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

This function returns the signed fractional portion of x. There is no error return.

Parameters

x

Floating-point value

intptr

Pointer to stored integer portion

Remarks

The modf function breaks down the floating-point value x into fractional and integer parts, each of which has the same sign as x. The signed fractional portion of x is returned. The integer portion is stored as a floating-point value at intptr.

Example

/* MODF.C */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x, y, n;

   x = -14.87654321;      /* Divide x into its fractional */
   y = modf( x, &n );     /* and integer parts            */

   printf( "For %f, the fraction is %f and the integer is %.f\n",
           x, y, n );
}

Output

For -14.876543, the fraction is -0.876543 and the integer is -14

Floating-Point Support Routines, Long Double

See Also frexp, ldexp


_msize

Returns the size of a memory block allocated in the heap.

size_t _msize( void *memblock );

Routine | Required Header | Compatibility
_msize | <malloc.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_msize returns the size (in bytes) as an unsigned integer.

Parameter

memblock

Pointer to memory block

Remarks

The _msize function returns the size, in bytes, of the memory block allocated by a call to calloc, malloc, or realloc.

When the application is linked with a debug version of the C run-time libraries, _msize resolves to _msize_dbg. For more information about how the heap is managed during the debugging process, see Using C Run-Time Library Debugging Support.

Example

/* REALLOC.C: This program allocates a block of memory for
 * buffer and then uses _msize to display the size of that
 * block. Next, it uses realloc to expand the amount of
 * memory used by buffer and then calls _msize again to
 * display the new amount of memory allocated to buffer.
 */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

void main( void )
{
   long *buffer;
   size_t size;

   if( (buffer = (long *)malloc( 1000 * sizeof( long ) )) == NULL )
      exit( 1 );

   size = _msize( buffer );
   printf( "Size of block after malloc of 1000 longs: %u\n", size );

   /* Reallocate and show new size: */
   if( (buffer = realloc( buffer, size + (1000 * sizeof( long )) ))
        ==  NULL )
      exit( 1 );
   size = _msize( buffer );
   printf( "Size of block after realloc of 1000 more longs: %u\n",
            size );

   free( buffer );
   exit( 0 );
}

Output

Size of block after malloc of 1000 longs: 4000
Size of block after realloc of 1000 more longs: 8000

Memory Allocation Routines

See Also calloc, _expand, malloc, realloc


_nextafter

Returns next representable neighbor.

double _nextafter( double x, double y );

Routine | Required Header | Compatibility
_nextafter | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If x=y, _nextafter returns x, with no exception triggered. If either x or y is a quiet NaN, then the return value is one or the other of the input NaNs.

Parameters

x, y

Double-precision floating-point values

Remarks

The _nextafter function returns the closest representable neighbor of x in the direction toward y.

Floating-Point Support Routines

See Also _isnan


offsetof

Retrieves the offset of a member from the beginning of its parent structure.

size_t offsetof( structName, memberName );

Routine | Required Header | Compatibility
offsetof | <stddef.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

offsetof returns the offset in bytes of the specified member from the beginning of its parent data structure. It is undefined for bit fields.

Parameters

structName

Name of the parent data structure

memberName

Name of the member in the parent data structure for which to determine the offset

Remarks

The offsetof macro returns the offset in bytes of memberName from the beginning of the structure specified by structName. You can specify types with the struct keyword.

Note offsetof is not a function and cannot be described using a C prototype.


_onexit

Registers a routine to be called at exit time.

_onexit_t _onexit( _onexit_t func );

Routine | Required Header | Compatibility
_onexit | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_onexit returns a pointer to the function if successful, or NULL if there is no space to store the function pointer.

Parameter

func

Pointer to function to be called at exit

Remarks

The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.

_onexit is a Microsoft extension. For ANSI portability use atexit.

Example

/* ONEXIT.C */

#include <stdlib.h>
#include <stdio.h>

/* Prototypes */
int fn1(void), fn2(void), fn3(void), fn4 (void);

void main( void )
{
   _onexit( fn1 );
   _onexit( fn2 );
   _onexit( fn3 );
   _onexit( fn4 );
   printf( "This is executed first.\n" );
}

int fn1()
{
   printf( "next.\n" );
   return 0;
}

int fn2()
{
   printf( "executed " );
   return 0;
}

int fn3()
{
   printf( "is " );
   return 0;
}

int fn4()
{
   printf( "This " );
   return 0;
}

Output

This is executed first.
This is executed next.

Process and Environment Control Routines

See Also atexit, exit


_open, _wopen

Open a file.

int _open( const char *filename, int oflag [, int pmode] );

int _wopen( const wchar_t *filename, int oflag [, int pmode] );

Routine | Required Header | Optional Headers | Compatibility
_open | <io.h> | <fcntl.h>, <sys/types.h>, <sys/stat.h> | Win 95, Win NT
_wopen | <io.h> or <wchar.h> | <fcntl.h>, <sys/types.h>, <sys/stat.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a file handle for the opened file. A return value of –1 indicates an error, in which case errno is set to one of the following values:

EACCES

Tried to open read-only file for writing, or file’s sharing mode does not allow specified operations, or given path is directory

EEXIST

_O_CREAT and _O_EXCL flags specified, but filename already exists

EINVAL

Invalid oflag or pmode argument

EMFILE

No more file handles available (too many open files)

ENOENT

File or path not found

Parameters

filename

Filename

oflag

Type of operations allowed

pmode

Permission mode

Remarks

The _open function opens the file specified by filename and prepares the file for reading or writing, as specified by oflag. _wopen is a wide-character version of _open; the filename argument to _wopen is a wide-character string. _wopen and _open behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_topen | _open | _open | _wopen

oflag is an integer expression formed from one or more of the following manifest constants or constant combinations defined in FCNTL.H:

_O_APPEND

Moves file pointer to end of file before every write operation.

_O_BINARY

Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)

_O_CREAT

Creates and opens new file for writing. Has no effect if file specified by filename exists. pmode argument is required when _O_CREAT is specified.

_O_CREAT | _O_SHORT_LIVED

Create file as temporary and if possible do not flush to disk. pmode argument is required when _O_CREAT is specified.

_O_CREAT | _O_TEMPORARY

Create file as temporary; file is deleted when last file handle is closed. pmode argument is required when _O_CREAT is specified.

_O_CREAT | _O_EXCL

Returns error value if file specified by filename exists. Applies only when used with _O_CREAT.

_O_RANDOM

Specifies primarily random access from disk

_O_RDONLY

Opens file for reading only; cannot be specified with _O_RDWR or _O_WRONLY.

_O_RDWR

Opens file for both reading and writing; you cannot specify this flag with _O_RDONLY or _O_WRONLY.

_O_SEQUENTIAL

Specifies primarily sequential access from disk

_O_TEXT

Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)

_O_TRUNC

Opens file and truncates it to zero length; file must have write permission. You cannot specify this flag with _O_RDONLY. _O_TRUNC used with _O_CREAT opens an existing file or creates a new file.

Warning The _O_TRUNC flag destroys the contents of the specified file.

_O_WRONLY

Opens file for writing only; cannot be specified with _O_RDONLY or _O_RDWR.

To specify the file access mode, you must specify either _O_RDONLY, _O_RDWR, or _O_WRONLY. There is no default value for the access mode.

When two or more manifest constants are used to form the oflag argument, the constants are combined with the bitwise-OR operator ( | ). See Text and Binary Mode File I/O for a discussion of binary and text modes.

The pmode argument is required only when _O_CREAT is specified. If the file already exists, pmode is ignored. Otherwise, pmode specifies the file permission settings, which are set when the new file is closed the first time. _open applies the current file-permission mask to pmode before setting the permissions (for more information, see _umask). pmode is an integer expression containing one or both of the following manifest constants, defined in SYS\STAT.H:

_S_IREAD

Reading only permitted

_S_IWRITE

Writing permitted (effectively permits reading and writing)

_S_IREAD | _S_IWRITE

Reading and writing permitted

When both constants are given, they are joined with the bitwise-OR operator ( | ). In Windows NT, all files are readable, so write-only permission is not available; thus the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent.

Example

/* OPEN.C: This program uses _open to open a file
 * named OPEN.C for input and a file named OPEN.OUT
 * for output. The files are then closed.
 */

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdio.h>

void main( void )
{
   int fh1, fh2;

   fh1 = _open( "OPEN.C", _O_RDONLY );
   if( fh1 == -1 )
      perror( "open failed on input file" );
   else
   {
      printf( "open succeeded on input file\n" );
      _close( fh1 );
   }

   fh2 = _open( "OPEN.OUT", _O_WRONLY | _O_CREAT, _S_IREAD |
                            _S_IWRITE );
   if( fh2 == -1 )
      perror( "Open failed on output file" );
   else
   {
      printf( "Open succeeded on output file\n" );
      _close( fh2 );
   }
}

Output

Open succeeded on input file
Open succeeded on output file

Low-Level I/O Routines

See Also _chmod, _close, _creat, _dup, fopen, _sopen


_open_osfhandle

Associates a C run-time file handle with a existing operating-system file handle.

int _open_osfhandle ( long osfhandle, int flags );

Routine | Required Header | Compatibility
_open_osfhandle | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _open_osfhandle returns a C run-time file handle. Otherwise, it returns –1.

Parameters

osfhandle

Operating-system file handle

flags

Types of operations allowed

Remarks

The _open_osfhandle function allocates a C run-time file handle and sets it to point to the operating-system file handle specified by osfhandle. The flags argument is an integer expression formed from one or more of the manifest constants defined in FCNTL.H. When two or more manifest constants are used to form the flags argument, the constants are combined with the bitwise-OR operator ( | ).

The FCNTL.H file defines the following manifest constants:

_O_APPEND

Positions file pointer to end of file before every write operation.

_O_RDONLY

Opens file for reading only

_O_TEXT

Opens file in text (translated) mode

File Handling Routines


_outp, _outpw, _outpd

Output a byte(_outp), a word(_outpw), or a double word (_outpd) at a port.

int _outp( unsigned short port, int databyte );

unsigned short _outpw( unsigned short port, unsigned short dataword );

unsigned long _outpd( unsigned short port, unsigned long dataword );

Routine | Required Header | Compatibility
_outp | <conio.h> | Win 95
_outpw | <conio.h> | Win 95
_outpd | <conio.h> | Win 95

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The functions return the data output. There is no error return.

Parameters

port

Port number

databyte, dataword

Output values

Remarks

The _outp, _outpw, and _outpd functions write a byte, a word, and a double word, respectively, to the specified output port. The port argument can be any unsigned integer in the range 0 – 65,535; databyte can be any integer in the range 0 – 255; and dataword can be any value in the range of an integer, an unsigned short integer, and an unsigned long integer, respectively.

Console and Port I/O Routines

See Also _inp


_pclose

Waits for new command processor and closes stream on associated pipe.

int _pclose( FILE *stream );

Routine | Required Header | Compatibility
_pclose | <stdio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_pclose returns the exit status of the terminating command processor, or –1 if an error occurs. The format of the return value is the same as that for _cwait, except the low-order and high-order bytes are swapped.

Parameter

stream

Return value from previous call to _popen

Remarks

The _pclose function looks up the process ID of the command processor (CMD.EXE) started by the associated _popen call, executes a _cwait call on the new command processor, and closes the stream on the associated pipe.

Process and Environment Control Routines

See Also _pipe, _popen


perror, _wperror

Print an error message.

void perror( const char *string );

void _wperror( const wchar_t *string );

Routine | Required Header | Compatibility
perror | <stdio.h> or <stdlib.h> | ANSI, Win 95, Win NT
_wperror | <stdio.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

string

String message to print

Remarks

The perror function prints an error message to stderr. _wperror is a wide-character version of _perror; the string argument to _wperror is a wide-character string. _wperror and _perror behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tperror | perror | perror | _wperror

string is printed first, followed by a colon, then by the system error message for the last library call that produced the error, and finally by a newline character. If string is a null pointer or a pointer to a null string, perror prints only the system error message.

The error number is stored in the variable errno (defined in ERRNO.H). The system error messages are accessed through the variable _sys_errlist, which is an array of messages ordered by error number. perror prints the appropriate error message using the errno value as an index to _sys_errlist. The value of the variable _sys_nerr is defined as the maximum number of elements in the _sys_errlist array.

For accurate results, call perror immediately after a library routine returns with an error. Otherwise, subsequent calls can overwrite the errno value.

In Windows NT and Windows 95, some errno values listed in ERRNO.H are unused. These values are reserved for use by the UNIX operating system. See _doserrno, errno, _sys_errlist, and _sys_nerr for a listing of errno values used by Windows NT and Windows 95. perror prints an empty string for any errno value not used by these platforms.

Example

/* PERROR.C: This program attempts to open a file named
 * NOSUCHF.ILE. Because this file probably doesn't exist,
 * an error message is displayed. The same message is
 * created using perror, strerror, and _strerror.
 */

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void main( void )
{
   int  fh;

   if( (fh = _open( "NOSUCHF.ILE", _O_RDONLY )) == -1 )
   {
      /* Three ways to create error message: */
      perror( "perror says open failed" );
      printf( "strerror says open failed: %s\n", strerror( errno ) );
      printf( _strerror( "_strerror says open failed" ) );
   }
   else
   {
      printf( "open succeeded on input file\n" );
      _close( fh );
   }
}

Output

perror says open failed: No such file or directory

strerror says open failed: No such file or directory
_strerror says open failed: No such file or directory

Process and Environment Control Routines

See Also clearerr, ferror, strerror


_pipe

Creates a pipe for reading and writing.

int _pipe( int *phandles, unsigned int psize, int textmode );

Routine | Required Header | Optional Headers | Compatibility
_pipe | <io.h> | <fcntl.h>,1 <errno.h>2 | Win 95, Win NT

1 For _O_BINARY and _O_TEXT definitions.

2 errno definitions.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_pipe returns 0 if successful. It returns –1 to indicate an error, in which case errno is set to one of two values: EMFILE, which indicates no more file handles available, or ENFILE, which indicates a system file table overflow.

Parameters

phandles[2]

Array to hold read and write handles

psize

Amount of memory to reserve

textmode

File mode

Remarks

The _pipe function creates a pipe. A pipe is an artificial I/O channel that a program uses to pass information to other programs. A pipe is similar to a file in that it has a file pointer, a file descriptor, or both, and can be read from or written to using the standard library’s input and output functions. However, a pipe does not represent a specific file or device. Instead, it represents temporary storage in memory that is independent of the program’s own memory and is controlled entirely by the operating system.

_pipe is similar to _open but opens the pipe for reading and writing, returning two file handles instead of one. The program can use both sides of the pipe or close the one it does not need. For example, the command processor in Windows NT creates a pipe when executing a command such as

PROGRAM1 | PROGRAM2

The standard output handle of PROGRAM1 is attached to the pipe’s write handle. The standard input handle of PROGRAM2 is attached to the pipe’s read handle. This eliminates the need for creating temporary files to pass information to other programs.

The _pipe function returns two handles to the pipe in the phandles argument. The element phandles[0] contains the read handle, and the element phandles[1] contains the write handle. Pipe file handles are used in the same way as other file handles. (The low-level input and output functions _read and _write can read from and write to a pipe.) To detect the end-of-pipe condition, check for a _read request that returns 0 as the number of bytes read.

The psize argument specifies the amount of memory, in bytes, to reserve for the pipe. The textmode argument specifies the translation mode for the pipe. The manifest constant _O_TEXT specifies a text translation, and the constant _O_BINARY specifies binary translation. (See fopen for a description of text and binary modes.) If the textmode argument is 0, _pipe uses the default translation mode specified by the default-mode variable _fmode.

In multithreaded programs, no locking is performed. The handles returned are newly opened and should not be referenced by any thread until after the _pipe call is complete.

In order to use the _pipe function to communicate between a parent and a child process, each process must have only one handle open on the pipe. The handles must be opposites: if the parent has a read handle open, then the child must have a write handle open. The easiest way to do this is to OR (|) the _O_NOINHERIT flag with textmode. Then, use _dup or _dup2 to create an inheritable copy of the pipe handle you wish to pass to the child. Close the original handle, and spawn the child process. Upon returning from the spawn call, close the 'duplicate' handle in the parent process. See Example 2 below for more information.

In Windows NT and Windows 95, a pipe is destroyed when all of its handles have been closed. (If all read handles on the pipe have been closed, writing to the pipe causes an error.) All read and write operations on the pipe wait until there is enough data or enough buffer space to complete the I/O request.

Example 1

/* PIPE.C: This program uses the _pipe function to pass streams of
 * text to spawned processes.
 */

#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <fcntl.h>
#include <process.h>
#include <math.h>

enum PIPES { READ, WRITE }; /* Constants 0 and 1 for READ and WRITE */
#define NUMPROBLEM 8

void main( int argc, char *argv[] )
{

   int hpipe[2];
   char hstr[20];
   int pid, problem, c;
   int termstat;

   /* If no arguments, this is the spawning process */
   if( argc == 1 )
   {

      setvbuf( stdout, NULL, _IONBF, 0 );

      /* Open a set of pipes */
      if( _pipe( hpipe, 256, O_BINARY ) == -1 )
          exit( 1 );

      /* Convert pipe read handle to string and pass as argument
       * to spawned program. Program spawns itself (argv[0]).
       */
      itoa( hpipe[READ], hstr, 10 );
      if( ( pid = spawnl( P_NOWAIT, argv[0], argv[0],
            hstr, NULL ) ) == -1 )
          printf( "Spawn failed" );

      /* Put problem in write pipe. Since spawned program is
       * running simultaneously, first solutions may be done
       * before last problem is given.
       */
      for( problem = 1000; problem <= NUMPROBLEM * 1000; problem += 1000)
      {

         printf( "Son, what is the square root of %d?\n", problem );
         write( hpipe[WRITE], (char *)&problem, sizeof( int ) );

      }

      /* Wait until spawned program is done processing. */
      _cwait( &termstat, pid, WAIT_CHILD );
      if( termstat & 0x0 )
         printf( "Child failed\n" );

      close( hpipe[READ] );
      close( hpipe[WRITE] );

   }

   /* If there is an argument, this must be the spawned process. */
   else
   {

      /* Convert passed string handle to integer handle. */
      hpipe[READ] = atoi( argv[1] );

      /* Read problem from pipe and calculate solution. */
      for( c = 0; c < NUMPROBLEM; c++ )
      {

        read( hpipe[READ], (char *)&problem, sizeof( int ) );
        printf( "Dad, the square root of %d is %3.2f.\n",
                 problem, sqrt( ( double )problem ) );

      }
   }
}

Output

Son, what is the square root of 1000?
Son, what is the square root of 2000?
Son, what is the square root of 3000?
Son, what is the square root of 4000?
Son, what is the square root of 5000?
Son, what is the square root of 6000?
Son, what is the square root of 7000?
Son, what is the square root of 8000?
Dad, the square root of 1000 is 31.62.
Dad, the square root of 2000 is 44.72.
Dad, the square root of 3000 is 54.77.
Dad, the square root of 4000 is 63.25.
Dad, the square root of 5000 is 70.71.
Dad, the square root of 6000 is 77.46.
Dad, the square root of 7000 is 83.67.
Dad, the square root of 8000 is 89.44.

Example 2

// This is a simple filter application.  It will spawn
// the application on  command line. But before spawning
// the application, it will create a pipe that will direct the
// spawned application's stdout to the filter.  The filter
// will remove ASCII 7 (beep) characters.

// Beeper.Cpp

/* Compile options needed: None */
#include <stdio.h>
#include <string.h>

int main()
{
   int   i;
   for(i=0;i<100;++i)
      {
         printf("\nThis is speaker beep number %d... \n\7", i+1);
      }
   return 0;
}

// BeepFilter.Cpp
/* Compile options needed: none
   Execute as: BeepFilter.exe <path>Beeper.exe
*/
#include <windows.h>
#include <process.h>
#include <memory.h>
#include <string.h>
#include <stdio.h>
#include <fcntl.h>
#include <io.h>

#define   OUT_BUFF_SIZE 512
#define   READ_HANDLE 0
#define   WRITE_HANDLE 1
#define   BEEP_CHAR 7

char szBuffer[OUT_BUFF_SIZE];

int Filter(char* szBuff, ULONG nSize, int nChar)
{
   char* szPos = szBuff + nSize -1;
   char* szEnd = szPos;
   int nRet = nSize;

   while (szPos > szBuff)
   {
      if (*szPos == nChar)
         {
            memmove(szPos, szPos+1, szEnd - szPos);
            --nRet;
         }
      --szPos;
   }
   return nRet;
}

int main(int argc, char** argv)
{
   int nExitCode = STILL_ACTIVE;
   if (argc >= 2)
   {
      HANDLE hProcess;
      int hStdOut;
      int hStdOutPipe[2];

      // Create the pipe
      if(_pipe(hStdOutPipe, 512, O_BINARY | O_NOINHERIT) == -1)
         return   1;

      // Duplicate stdout handle (next line will close original)
      hStdOut = _dup(_fileno(stdout));

      // Duplicate write end of pipe to stdout handle
      if(_dup2(hStdOutPipe[WRITE_HANDLE], _fileno(stdout)) != 0)
         return   2;

      // Close original write end of pipe
      close(hStdOutPipe[WRITE_HANDLE]);

      // Spawn process
      hProcess = (HANDLE)spawnvp(P_NOWAIT, argv[1],
       (const char* const*)&argv[1]);

      // Duplicate copy of original stdout back into stdout
      if(_dup2(hStdOut, _fileno(stdout)) != 0)
         return   3;

      // Close duplicate copy of original stdout
      close(hStdOut);

      if(hProcess)
      {
         int nOutRead;
         while   (nExitCode == STILL_ACTIVE)
         {
            nOutRead = read(hStdOutPipe[READ_HANDLE],
             szBuffer, OUT_BUFF_SIZE);
            if(nOutRead)
            {
               nOutRead = Filter(szBuffer, nOutRead, BEEP_CHAR);
               fwrite(szBuffer, 1, nOutRead, stdout);
            }

            if(!GetExitCodeProcess(hProcess,(unsigned long*)&nExitCode))
               return 4;
         }
      }
   }

   printf("\nPress \'ENTER\' key to continue... ");
   getchar();
   return nExitCode;
}

Process and Environment Control Routines

See Also _open


_popen, _wpopen

Creates a pipe and executes a command.

FILE *_popen( const char *command, const char *mode );

FILE *_wpopen( const wchar_t *command, const wchar_t *mode );

Routine | Required Header | Compatibility
_popen | <stdio.h> | Win 95, Win NT
_wpopen | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a stream associated with one end of the created pipe. The other end of the pipe is associated with the spawned command’s standard input or standard output. The functions return NULL on an error.

Parameters

command

Command to be executed

mode

Mode of returned stream

Remarks

The _popen function creates a pipe and asynchronously executes a spawned copy of the command processor with the specified string command. The character string mode specifies the type of access requested, as follows:

"r"

The calling process can read the spawned command’s standard output via the returned stream.

"w"

The calling process can write to the spawned command’s standard input via the returned stream.

"b"

Open in binary mode.

"t"

Open in text mode.

Note The _popen function returns an invalid file handle, if used in a Windows program, that will cause the program to hang indefinitely. _popen works properly in a Console application. To create a Windows application that redirects input and output, read the section "Creating a Child Process with Redirected Input and Output" in the Win32 SDK.

_wpopen is a wide-character version of _popen; the path argument to _wpopen is a wide-character string. _wpopen and _popen behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tpopen | _popen | _popen | _wpopen

Example

/* POPEN.C: This program uses _popen and _pclose to receive a
 * stream of text from a system process.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{

   char   psBuffer[128];
   FILE   *chkdsk;

        /* Run DIR so that it writes its output to a pipe. Open this
    * pipe with read text attribute so that we can read it
         * like a text file.
    */
   if( (chkdsk = _popen( "dir *.c /on /p", "rt" )) == NULL )
      exit( 1 );

   /* Read pipe until end of file. End of file indicates that
    * CHKDSK closed its standard out (probably meaning it
         * terminated).
    */
   while( !feof( chkdsk ) )
   {
      if( fgets( psBuffer, 128, chkdsk ) != NULL )
         printf( psBuffer );
   }

   /* Close pipe and print return value of CHKDSK. */
   printf( "\nProcess returned %d\n", _pclose( chkdsk ) );
}

Output

 Volume in drive C is CDRIVE
 Volume Serial Number is 0E17-1702

 Directory of C:\dolphin\crt\code\pcode

05/02/94  01:05a                   805 perror.c
05/02/94  01:05a                 2,149 pipe.c
05/02/94  01:05a                   882 popen.c
05/02/94  01:05a                   206 pow.c
05/02/94  01:05a                 1,514 printf.c
05/02/94  01:05a                   454 putc.c
05/02/94  01:05a                   162 puts.c
05/02/94  01:05a                   654 putw.c
               8 File(s)          6,826 bytes
                             86,597,632 bytes free

Process returned 0

Process and Environment Control Routines

See Also _pclose, _pipe


pow

Calculates x raised to the power of y.

double pow( double x, double y );

Routine | Required Header | Compatibility
pow | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

pow returns the value of xy. No error message is printed on overflow or underflow.

Values of x and y | Return Value of pow
x < > 0 and y = 0.0 | 1
x = 0.0 and y = 0.0 | 1
x = 0.0 and y < 0 | INF

Parameters

x

Base

y

Exponent

Remarks

The pow function computes x raised to the power of y.

pow does not recognize integral floating-point values greater than 264, such as 1.0E100.

Example

/* POW.C
 *
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double x = 2.0, y = 3.0, z;

   z = pow( x, y );
   printf( "%.1f to the power of %.1f is %.1f\n", x, y, z );
}

Output

2.0 to the power of 3.0 is 8.0

Floating-Point Support Routines

See Also exp, log, sqrt


printf, wprintf

Print formatted output to the standard output stream.

int printf( const char *format [, argument]... );

int wprintf( const wchar_t *format [, argument]... );

Routine | Required Header | Compatibility
printf | <stdio.h> | ANSI, Win 95, Win NT
wprintf | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the number of characters printed, or a negative value if an error occurs.

Parameters

format

Format control

argument

Optional arguments

Remarks

The printf function formats and prints a series of characters and values to the standard output stream, stdout. If arguments follow the format string, the format string must contain specifications that determine the output format for the arguments. printf and fprintf behave identically except that printf writes output to stdout rather than to a destination of type FILE.

wprintf is a wide-character version of printf; format is a wide-character string. wprintf and printf behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tprintf | printf | printf | wprintf

The format argument consists of ordinary characters, escape sequences, and (if arguments follow format) format specifications. The ordinary characters and escape sequences are copied to stdout in order of their appearance. For example, the line

printf("Line one\n\t\tLine two\n");

produces the output

Line one
        Line two

Format specifications always begin with a percent sign (%) and are read left to right. When printf encounters the first format specification (if any), it converts the value of the first argument after format and outputs it accordingly. The second format specification causes the second argument to be converted and output, and so on. If there are more arguments than there are format specifications, the extra arguments are ignored. The results are undefined if there are not enough arguments for all the format specifications.

Example

/* PRINTF.C: This program uses the printf and wprintf functions
 * to produce formatted output.
 */

#include <stdio.h>

void main( void )
{
   char   ch = 'h', *string = "computer";
   int    count = -9234;
   double fp = 251.7366;
   wchar_t wch = L'w', *wstring = L"Unicode";

   /* Display integers. */
   printf( "Integer formats:\n"
           "\tDecimal: %d  Justified: %.6d  Unsigned: %u\n",
           count, count, count, count );

   printf( "Decimal %d as:\n\tHex: %Xh  C hex: 0x%x  Octal: %o\n",
            count, count, count, count );

   /* Display in different radixes. */
   printf( "Digits 10 equal:\n\tHex: %i  Octal: %i  Decimal: %i\n",
            0x10, 010, 10 );

   /* Display characters. */

   printf("Characters in field (1):\n%10c%5hc%5C%5lc\n", ch, ch, wch, wch);
   wprintf(L"Characters in field (2):\n%10C%5hc%5c%5lc\n", ch, ch, wch, wch);

   /* Display strings. */

   printf("Strings in field (1):\n%25s\n%25.4hs\n\t%S%25.3ls\n",
   string, string, wstring, wstring);
   wprintf(L"Strings in field (2):\n%25S\n%25.4hs\n\t%s%25.3ls\n",
       string, string, wstring, wstring);

   /* Display real numbers. */
   printf( "Real numbers:\n\t%f %.2f %e %E\n", fp, fp, fp, fp );

   /* Display pointer. */
   printf( "\nAddress as:\t%p\n", &count);

   /* Count characters printed. */
   printf( "\nDisplay to here:\n" );
   printf( "1234567890123456%n78901234567890\n", &count );
   printf( "\tNumber displayed: %d\n\n", count );
}

Output

Integer formats:
   Decimal: -9234  Justified: -009234  Unsigned: 4294958062
Decimal -9234 as:
   Hex: FFFFDBEEh  C hex: 0xffffdbee  Octal: 37777755756
Digits 10 equal:
   Hex: 16  Octal: 8  Decimal: 10
Characters in field (1):
         h    h    w    w
Characters in field (2):
         h    h    w    w
Strings in field (1):
                 computer
                     comp
   Unicode                      Uni
Strings in field (2):
                 computer
                     comp
   Unicode                      Uni
Real numbers:
   251.736600 251.74 2.517366e+002 2.517366E+002

Address as:   0012FFAC

Display to here:
123456789012345678901234567890
   Number displayed: 16

Floating-Point Support Routines | Stream I/O Routines | Locale Routines

See Also fopen, fprintf, scanf, sprintf, vprintf Functions


Format Specification Fields: printf and wprintf Functions

A format specification, which consists of optional and required fields, has the following form:

%[flags] [width] [. precision] [{h | l | I64 | L}]type

Each field of the format specification is a single character or a number signifying a particular format option. The simplest format specification contains only the percent sign and a type character (for example, %s). If a percent sign is followed by a character that has no meaning as a format field, the character is copied to stdout. For example, to print a percent-sign character, use %%.

The optional fields, which appear before the type character, control other aspects of the formatting, as follows:

type

Required character that determines whether the associated argument is interpreted as a character, a string, or a number (see Table R.3).

flags

Optional character or characters that control justification of output and printing of signs, blanks, decimal points, and octal and hexadecimal prefixes (see Table R.4). More than one flag can appear in a format specification.

width

Optional number that specifies the minimum number of characters output. (See printf Width Specification.)

precision

Optional number that specifies the maximum number of characters printed for all or part of the output field, or the minimum number of digits printed for integer values (see Table R.5).

h | l | I64 | L

Optional prefixes to type-that specify the size of argument (see Table R.6).


printf Type Field Characters

The type character is the only required format field ; it appears after any optional format fields. The type character determines whether the associated argument is interpreted as a character, string, or number. The types C and S, and the behavior of c and s with printf functions, are Microsoft extensions and are not ANSI-compatible.

Table R.3 printf Type Field Characters

Character | Type | Output Format
c | int or wint_t | When used with printf functions, specifies a single-byte character; when used with wprintf functions, specifies a wide character.
C | int or wint_t | When used with printf functions, specifies a wide character; when used with wprintf functions, specifies a single-byte character.
d | int | Signed decimal integer.
i | int | Signed decimal integer.
o | int | Unsigned octal integer.
u | int | Unsigned decimal integer.
x | int | Unsigned hexadecimal integer, using “abcdef.”
X | int | Unsigned hexadecimal integer, using “ABCDEF.”
e | double | Signed value having the form [ – ]d.dddd e [sign]ddd where d is a single decimal digit, dddd is one or more decimal digits, ddd is exactly three decimal digits, and sign is + or –.
E | double | Identical to the e format except that E rather than e introduces the exponent.
f | double | Signed value having the form [ – ]dddd.dddd, where dddd is one or more decimal digits. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision.
g | double | Signed value printed in f or e format, whichever is more compact for the given value and precision. The e format is used only when the exponent of the value is less than –4 or greater than or equal to the precision argument. Trailing zeros are truncated, and the decimal point appears only if one or more digits follow it.
G | double | Identical to the g format, except that E, rather than e, introduces the exponent (where appropriate).
n | Pointer to integer | Number of characters successfully written so far to the stream or buffer; this value is stored in the integer whose address is given as the argument.
p | Pointer to void | Prints the address pointed to by the argument in the form xxxx:yyyy where xxxx is the segment and yyyy is the offset, and the digits x and y are uppercase hexadecimal digits.
s | String | When used with printf functions, specifies a single-byte–character string; when used with wprintf functions, specifies a wide-character string. Characters are printed up to the first null character or until the precision value is reached.
S | String | When used with printf functions, specifies a wide-character string; when used with wprintf functions, specifies a single-byte–character string. Characters are printed up to the first null character or until the precision value is reached.


Flag Directives

The first optional field of the format specification is flags. A flag directive is a character that justifies output and prints signs, blanks, decimal points, and octal and hexadecimal prefixes. More than one flag directive may appear in a format specification.

Table R.4 Flag Characters

Flag | Meaning | Default
– | Left align the result within the given field width. | Right align.
+ | Prefix the output value with a sign (+ or –) if the output value is of a signed type. | Sign appears only for negative signed values (–).
0 | If width is prefixed with 0, zeros are added until the minimum width is reached. If 0 and – appear, the 0 is ignored. If 0 is specified with an integer format (i, u, x, X, o, d) the 0 is ignored. | No padding.
blank (' ') | Prefix the output value with a blank if the output value is signed and positive; the blank is ignored if both the blank and + flags appear. | No blank appears.
# | When used with the o, x, or X format, the # flag prefixes any nonzero output value with 0, 0x, or 0X, respectively. | No blank appears.
 | When used with the e, E, or f format, the # flag forces the output value to contain a decimal point in all cases. | Decimal point appears only if digits follow it.
 | When used with the g or G format, the # flag forces the output value to contain a decimal point in all cases and prevents the truncation of trailing zeros. Ignored when used with c, d, i, u, or s. | Decimal point appears only if digits follow it. Trailing zeros are truncated.


printf Width Specification

The second optional field of the format specification is the width specification. The width argument is a nonnegative decimal integer controlling the minimum number of characters printed. If the number of characters in the output value is less than the specified width, blanks are added to the left or the right of the values — depending on whether the – flag (for left alignment) is specified — until the minimum width is reached. If width is prefixed with 0, zeros are added until the minimum width is reached (not useful for left-aligned numbers).

The width specification never causes a value to be truncated. If the number of characters in the output value is greater than the specified width, or if width is not given, all characters of the value are printed (subject to the precision specification).

If the width specification is an asterisk (*), an int argument from the argument list supplies the value. The width argument must precede the value being formatted in the argument list. A nonexistent or small field width does not cause the truncation of a field; if the result of a conversion is wider than the field width, the field expands to contain the conversion result.


Precision Specification

The third optional field of the format specification is the precision specification. It specifies a nonnegative decimal integer, preceded by a period (.), which specifies the number of characters to be printed, the number of decimal places, or the number of significant digits (see Table R.5). Unlike the width specification, the precision specification can cause either truncation of the output value or rounding of a floating-point value. If precision is specified as 0 and the value to be converted is 0, the result is no characters output, as shown below:

printf( "%.0d", 0 );      /* No characters output */

If the precision specification is an asterisk (*), an int argument from the argument list supplies the value. The precision argument must precede the value being formatted in the argument list.

The type determines the interpretation of precision and the default when precision is omitted, as shown in Table R.5.

Table R.5 How Precision Values Affect Type

Type | Meaning | Default
c, C | The precision has no effect. | Character is printed.
d, i, u, o, x, X | The precision specifies the minimum number of digits to be printed. If the number of digits in the argument is less than precision, the output value is padded on the left with zeros. The value is not truncated when the number of digits exceeds precision. | Default precision is 1.
e, E | The precision specifies the number of digits to be printed after the decimal point. The last printed digit is rounded. | Default precision is 6; if precision is 0 or the period (.) appears without a number following it, no decimal point is printed.
f | The precision value specifies the number of digits after the decimal point. If a decimal point appears, at least one digit appears before it. The value is rounded to the appropriate number of digits. | Default precision is 6; if precision is 0, or if the period (.) appears without a number following it, no decimal point is printed.
g, G | The precision specifies the maximum number of significant digits printed. | Six significant digits are printed, with any trailing zeros truncated.
s, S | The precision specifies the maximum number of characters to be printed. Characters in excess of precision are not printed. | Characters are printed until a null character is encountered.

If the argument corresponding to a floating-point specifier is infinite, indefinite, or NaN, printf gives the following output.

Value | Output
+ infinity | 1.#INF random-digits
– infinity | –1.#INF random-digits
Indefinite (same as quiet NaN) | digit.#IND random-digits
NAN | digit.#NAN random-digits


Size and Distance Specification

The optional prefixes to type, h, l, and L, specify the “size” of argument (long or short, single-byte character or wide character, depending upon the type specifier that they modify). These type-specifier prefixes are used with type characters in printf functions or wprintf functions to specify interpretation of arguments, as shown in the following table. These prefixes are Microsoft extensions and are not ANSI-compatible.

Table R.6 Size Prefixes for printf and wprintf Format-Type Specifiers

To Specify | Use Prefix | With Type Specifier
long int | l | d, i, o, x, or X
long unsigned int | l | u
short int | h | d, i, o, x, or X
short unsigned int | h | u
__int64 | I64 | d, i, o, u, x, or X
Single-byte character with printf functions | h | c or C
Single-byte character with wprintf functions | h | c or C
Wide character with printf functions | l | c or C
Wide character with wprintf functions | l | c or C
Single-byte – character string with printf functions | h | s or S
Single-byte – character string with wprintf functions | h | s or S
Wide-character string with printf functions | l | s or S
Wide-character string with wprintf functions | l | s or S

Thus to print single-byte or wide-characters with printf functions and wprintf functions, use format specifiers as follows.

To Print Character As | Use Function | With Format Specifier
single byte | printf | c, hc, or hC
single byte | wprintf | C, hc, or hC
wide | wprintf | c, lc, or lC
wide | printf | C, lc, or lC

To print strings with printf functions and wprintf functions, use the prefixes h and l analogously with format type-specifiers s and S.


putc, putwc, putchar, putwchar

Writes a character to a stream (putc, putwc) or to stdout (putchar, putwchar).

int putc( int c, FILE *stream );

wint_t putwc( wint_t c, FILE *stream );

int putchar( int c );

wint_t putwchar( wint_t c );

Routine | Required Header | Compatibility
putc | <stdio.h> | ANSI, Win 95, Win NT
putwc | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT
putchar | <stdio.h> | ANSI, Win 95, Win NT
putwchar | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the character written. To indicate an error or end-of-file condition, putc and putchar return EOF; putwc and putwchar return WEOF. For all four routines, use ferror or feof to check for an error or end of file.

Parameters

c

Character to be written

stream

Pointer to FILE structure

Remarks

The putc routine writes the single character c to the output stream at the current position. Any integer can be passed to putc, but only the lower 8 bits are written. The putchar routine is identical to putc( c, stdout ). For each routine, if a read error occurs, the error indicator for the stream is set. putc and putchar are similar to fputc and _fputchar, respectively, but are implemented both as functions and as macros (see Choosing Between Functions and Macros). putwc and putwchar are wide-character versions of putc and putchar, respectively.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_puttc | putc | putc | putwc
_puttchar | putchar | putchar | putwchar

Example

/* PUTC.C: This program uses putc to write buffer
 * to a stream. If an error occurs, the program
 * stops before writing the entire buffer.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char *p, buffer[] = "This is the line of output\n";
   int  ch;

   ch = 0;
   /* Make standard out the stream and write to it. */
   stream = stdout;
   for( p = buffer; (ch != EOF) && (*p != '\0'); p++ )
      ch = putc( *p, stream );
}

Output

This is the line of output

Stream I/O Routines

See Also fputc, getc


_putch

Writes a character to the console.

int _putch( int c );

Routine | Required Header | Compatibility
_putch | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The function returns c if successful, and EOF if not.

Parameter

c

Character to be output

Remarks

The _putch function writes the character c directly (without buffering) to the console.

Example

/* GETCH.C: This program reads characters from
 * the keyboard until it receives a 'Y' or 'y'.
 */

#include <conio.h>
#include <ctype.h>

void main( void )
{
   int ch;

   _cputs( "Type 'Y' when finished typing keys: " );
   do
   {
      ch = _getch();
      ch = toupper( ch );
   } while( ch != 'Y' );

   _putch( ch );
   _putch( '\r' );    /* Carriage return */
   _putch( '\n' );    /* Line feed       */
}

Output

Type 'Y' when finished typing keys: Y

Console and Port I/O Routines

See Also _cprintf, _getch


_putenv, _wputenv

Creates new environment variables; modifies or removes existing ones.

int _putenv( const char *envstring );

int _wputenv( const wchar_t *envstring );

Routine | Required Header | Compatibility
_putenv | <stdlib.h> | Win 95, Win NT
_wputenv | <stdlib.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_putenv and _wputenv return 0 if successful, or –1 in the case of an error.

Parameter

envstring

Environment-string definition

Remarks

The _putenv function adds new environment variables or modifies the values of existing environment variables. Environment variables define the environment in which a process executes (for example, the default search path for libraries to be linked with a program). _wputenv is a wide-character version of _putenv; the envstring argument to _wputenv is a wide-character string.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tputenv | _putenv | _putenv | _wputenv

The envstring argument must be a pointer to a string of the form varname=string, where varname is the name of the environment variable to be added or modified and string is the variable’s value. If varname is already part of the environment, its value is replaced by string; otherwise, the new varname variable and its string value are added to the environment. You can remove a variable from the environment by specifying an empty string — in other words, by specifying only varname=.

_putenv and _wputenv affect only the environment that is local to the current process; you cannot use them to modify the command-level environment. That is, these functions operate only on data structures accessible to the run-time library and not on the environment “segment” created for a process by the operating system. When the current process terminates, the environment reverts to the level of the calling process (in most cases, the operating-system level). However, the modified environment can be passed to any new processes created by _spawn, _exec, or system, and these new processes get any new items added by _putenv and _wputenv.

With regard to environment entries, observe the following cautions:

  • Do not change an environment entry directly; instead, use _putenv or _wputenv to change it. To modify the return value of _putenv or _wputenv without affecting the environment table, use _strdup or strcpy to make a copy of the string.

  • Never free a pointer to an environment entry, because the environment variable will then point to freed space. A similar problem can occur if you pass _putenv or _wputenv a pointer to a local variable, then exit the function in which the variable is declared.

getenv and _putenv use the global variable _environ to access the environment table; _wgetenv and _wputenv use _wenviron. _putenv and _wputenv may change the value of _environ and _wenviron, thus invalidating the envp argument to main and the_wenvp argument to wmain. Therefore, it is safer to use _environ or _wenviron to access the environment information. For more information about the relation of _putenv and _wputenv to global variables, see _environ, _wenviron.

Example

/* GETENV.C: This program uses getenv to retrieve
 * the LIB environment variable and then uses
 * _putenv to change it to a new value.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char *libvar;

   /* Get the value of the LIB environment variable. */
   libvar = getenv( "LIB" );

   if( libvar != NULL )
      printf( "Original LIB variable is: %s\n", libvar );

   /* Attempt to change path. Note that this only affects the environment
    * variable of the current process. The command processor's environment
    * is not changed.
    */
   _putenv( "LIB=c:\\mylib;c:\\yourlib" );

   /* Get new value. */
   libvar = getenv( "LIB" );

   if( libvar != NULL )
      printf( "New LIB variable is: %s\n", libvar );
}

Output

Original LIB variable is: C:\progra~1\devstu~1\vc\lib
New LIB variable is: c:\mylib;c:\yourlib

Process and Environment Control Routines

See Also getenv, _searchenv


puts, _putws

Write a string to stdout.

int puts( const char *string );

int _putws( const wchar_t *string );

Routine | Required Header | Compatibility
puts | <stdio.h> | ANSI, Win 95, Win NT
_putws | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these returns a nonnegative value if successful. If puts fails it returns EOF; if _putws fails it returns WEOF.

Parameter

string

Output string

Remarks

The puts function writes string to the standard output stream stdout, replacing the string’s terminating null character ('\0') with a newline character ('\n') in the output stream.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_putts | puts | puts | _putws

Example

/* PUTS.C: This program uses puts
 * to write a string to stdout.
 */

#include <stdio.h>

void main( void )
{
   puts( "Hello world from puts!" );
}

Output

Hello world from puts!

Stream I/O Routines

See Also fputs, gets


_putw

Writes an integer to a stream.

int _putw( int binint, FILE *stream );

Routine | Required Header | Compatibility
_putw | <stdio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_putw returns the value written. A return value of EOF may indicate an error. Because EOF is also a legitimate integer value, use ferror to verify an error.

Parameters

binint

Binary integer to be output

stream

Pointer to FILE structure

Remarks

The _putw function writes a binary value of type int to the current position of stream. _putw does not affect the alignment of items in the stream, nor does it assume any special alignment. _putw is primarily for compatibility with previous libraries. Portability problems may occur with _putw because the size of an int and the ordering of bytes within an int differ across systems.

Example

/* PUTW.C: This program uses _putw to write a
 * word to a stream, then performs an error check.
 */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   FILE *stream;
   unsigned u;
   if( (stream = fopen( "data.out", "wb" )) == NULL )
      exit( 1 );
   for( u = 0; u << 10; u++ )
   {
      _putw( u + 0x2132, stdout );
      _putw( u + 0x2132, stream );   /* Write word to stream. */
      if( ferror( stream ) )         /* Make error check. */
      {
         printf( "_putw failed" );
         clearerr( stream );
         exit( 1 );
      }
   }
   printf( "\nWrote ten words\n" );
   fclose( stream );
}

Output

Wrote ten words

Stream I/O Routines

See Also _getw


qsort

Performs a quick sort.

void qsort( void *base, size_t num, size_t width, int (__cdecl *compare )(const void *elem1, const void *elem2 ) );

Routine | Required Header | Compatibility
qsort | <stdlib.h> and <search.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

base

Start of target array

num

Array size in elements

width

Element size in bytes

compare

Comparison function

elem1

Pointer to the key for the search

elem2

Pointer to the array element to be compared with the key

Remarks

The qsort function implements a quick-sort algorithm to sort an array of num elements, each of width bytes. The argument base is a pointer to the base of the array to be sorted. qsort overwrites this array with the sorted elements. The argument compare is a pointer to a user-supplied routine that compares two array elements and returns a value specifying their relationship. qsort calls the compare routine one or more times during the sort, passing pointers to two array elements on each call:

compare( (void *) elem1, (void *) elem2 );

The routine must compare the elements, then return one of the following values:

Return Value | Description
< 0 | elem1 less than elem2
0 | elem1 equivalent to elem2
> 0 | elem1 greater than elem2

The array is sorted in increasing order, as defined by the comparison function. To sort an array in decreasing order, reverse the sense of “greater than” and “less than” in the comparison function.

Example

/* QSORT.C: This program reads the command-line
 * parameters and uses qsort to sort them. It
 * then displays the sorted arguments.
 */

#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int compare( const void *arg1, const void *arg2 );

void main( int argc, char **argv )
{
   int i;
   /* Eliminate argv[0] from sort: */
   argv++;
   argc--;

   /* Sort remaining args using Quicksort algorithm: */
   qsort( (void *)argv, (size_t)argc, sizeof( char * ), compare );

   /* Output sorted list: */
   for( i = 0; i < argc; ++i )
      printf( "%s ", argv[i] );
   printf( "\n" );
}

int compare( const void *arg1, const void *arg2 )
{
   /* Compare all of both strings: */
   return _stricmp( * ( char** ) arg1, * ( char** ) arg2 );
}

Output

[C:\code]qsort every good boy deserves favor
boy deserves every favor good

Searching and Sorting Routines

See Also bsearch, _lsearch


_query_new_handler

Returns address of current new handler routine.

_PNH _query_new_handler( void );

Routine | Required Header | Compatibility
_query_new_handler | <new.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_query_new_handler returns the address of the current new handler routine as set by _set_new_handler.

Remarks

The C++ _query_new_handler function returns the address of the current exception-handling function set by the C++ _set_new_handler function. _set_new_handler is used to specify an exception-handling function that is to gain control if the new operator fails to allocate memory. For more information, see the discussions of the operator new and operator delete functions in C++ Language Reference.

Memory Allocation Routines

See Also free


_query_new_mode

Returns an integer indicating new handler mode set by _set_new_mode for malloc.

int _query_new_mode( void );

Routine | Required Header | Compatibility
_query_new_mode | <new.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_query_new_mode returns the current new handler mode, namely 0 or 1, for malloc. A return value of 1 indicates that, on failure to allocate memory, malloc calls the new handler routine; a return value of 0 indicates that it does not.

Remarks

The C++ _query_new_mode function returns an integer that indicates the new handler mode that is set by the C++ _set_new_mode function for malloc. The new handler mode indicates whether, on failure to allocate memory, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure. You can use _set_new_mode to override this behavior so that on failure malloc calls the new handler routine in the same way that the new operator does when it fails to allocate memory. For more information, see the operator delete and operator new functions in C++ Language Reference.

Memory Allocation Routines

See Also calloc, free, realloc, _query_new_handler


raise

Sends a signal to the executing program.

int raise( int sig );

Routine | Required Header | Compatibility
raise | <signal.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, raise returns 0. Otherwise, it returns a nonzero value.

Parameter

sig

Signal to be raised

Remarks

The raise function sends sig to the executing program. If a previous call to signal has installed a signal-handling function for sig, raise executes that function. If no handler function has been installed, the default action associated with the signal value sig is taken, as follows.

Signal | Meaning | Default
SIGABRT | Abnormal termination | Terminates the calling program with exit code 3
SIGFPE | Floating-point error | Terminates the calling program
SIGILL | Illegal instruction | Terminates the calling program
SIGINT | CTRL+C interrupt | Terminates the calling program
SIGSEGV | Illegal storage access | Terminates the calling program
SIGTERM | Termination request sent to the program | Ignores the signal

Process and Environment Control Routines

See Also abort, signal


rand

Generates a pseudorandom number.

int rand( void );

Routine | Required Header | Compatibility
rand | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

rand returns a pseudorandom number, as described above. There is no error return.

Remarks

The rand function returns a pseudorandom integer in the range 0 to RAND_MAX. Use the srand function to seed the pseudorandom-number generator before calling rand.

Example

/* RAND.C: This program seeds the random-number generator
 * with the time, then displays 10 random integers.
 */

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void main( void )
{
   int i;

   /* Seed the random-number generator with current time so that
    * the numbers will be different every time we run.
    */
   srand( (unsigned)time( NULL ) );

   /* Display 10 numbers. */
   for( i = 0;   i < 10;i++ )
      printf( "  %6d\n", rand() );
}

Output

    6929
    8026
   21987
   30734
   20587
    6699
   22034
   25051
    7988
   10104

Floating-Point Support Routines

See Also srand


_read

Reads data from a file.

int _read( int handle, void *buffer, unsigned int count );

Routine | Required Header | Compatibility
_read | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_read returns the number of bytes read, which may be less than count if there are fewer than count bytes left in the file or if the file was opened in text mode, in which case each carriage return–linefeed (CR-LF) pair is replaced with a single linefeed character. Only the single linefeed character is counted in the return value. The replacement does not affect the file pointer.

If the function tries to read at end of file, it returns 0. If the handle is invalid, or the file is not open for reading, or the file is locked, the function returns –1 and sets errno to EBADF.

Parameters

handle

Handle referring to open file

buffer

Storage location for data

count

Maximum number of bytes

Remarks

The _read function reads a maximum of count bytes into buffer from the file associated with handle. The read operation begins at the current position of the file pointer associated with the given file. After the read operation, the file pointer points to the next unread character.

If the file was opened in text mode, the read terminates when _read encounters a CTRL+Z character, which is treated as an end-of-file indicator. Use _lseek to clear the end-of-file indicator.

Example

/* READ.C: This program opens a file named
 * READ.C and tries to read 60,000 bytes from
 * that file using _read. It then displays the
 * actual number of bytes read from READ.C.
 */

#include <fcntl.h>      /* Needed only for _O_RDWR definition */
#include <io.h>
#include <stdlib.h>
#include <stdio.h>

char buffer[60000];

void main( void )
{
   int fh;
   unsigned int nbytes = 60000, bytesread;

   /* Open file for input: */
   if( (fh = _open( "read.c", _O_RDONLY )) == -1 )
   {
      perror( "open failed on input file" );
      exit( 1 );
   }

   /* Read in input: */
   if( ( bytesread = _read( fh, buffer, nbytes ) ) <= 0 )
      perror( "Problem reading file" );
   else
      printf( "Read %u bytes from file\n", bytesread );

   _close( fh );
}

Output

Read 775 bytes from file

Low-Level I/O Routines

See Also _creat, fread, _open, _write


realloc

Reallocate memory blocks.

void *realloc( void *memblock, size_t size );

Routine | Required Header | Compatibility
realloc | <stdlib.h> and <malloc.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

realloc returns a void pointer to the reallocated (and possibly moved) memory block. The return value is NULL if the size is zero and the buffer argument is not NULL, or if there is not enough available memory to expand the block to the given size. In the first case, the original block is freed. In the second, the original block is unchanged. The return value points to a storage space that is guaranteed to be suitably aligned for storage of any type of object. To get a pointer to a type other than void, use a type cast on the return value.

Parameters

memblock

Pointer to previously allocated memory block

size

New size in bytes

Remarks

The realloc function changes the size of an allocated memory block. The memblock argument points to the beginning of the memory block. If memblock is NULL, realloc behaves the same way as malloc and allocates a new block of size bytes. If memblock is not NULL, it should be a pointer returned by a previous call to calloc, malloc, or realloc.

The size argument gives the new size of the block, in bytes. The contents of the block are unchanged up to the shorter of the new and old sizes, although the new block can be in a different location. Because the new block can be in a new memory location, the pointer returned by realloc is not guaranteed to be the pointer passed through the memblock argument.

realloc calls malloc in order to use the C++ _set_new_mode function to set the new handler mode. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when realloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. To override the default, call

_set_new_mode(1)

early in your program, or link with NEWMODE.OBJ.

When the application is linked with a debug version of the C run-time libraries, realloc resolves to _realloc_dbg. For more information about how the heap is managed during the debugging process, see Using C Run-Time Library Debugging Support.

Example

/* REALLOC.C: This program allocates a block of memory for
 * buffer and then uses _msize to display the size of that
 * block. Next, it uses realloc to expand the amount of
 * memory used by buffer and then calls _msize again to
 * display the new amount of memory allocated to buffer.
 */

#include <stdio.h>
#include <malloc.h>
#include <stdlib.h>

void main( void )
{
   long *buffer;
   size_t size;

   if( (buffer = (long *)malloc( 1000 * sizeof( long ) )) == NULL )
      exit( 1 );

   size = _msize( buffer );
   printf( "Size of block after malloc of 1000 longs: %u\n", size );

   /* Reallocate and show new size: */
   if( (buffer = realloc( buffer, size + (1000 * sizeof( long )) ))
        ==  NULL )
      exit( 1 );
   size = _msize( buffer );
   printf( "Size of block after realloc of 1000 more longs: %u\n",
            size );

   free( buffer );
   exit( 0 );
}

Output

Size of block after malloc of 1000 longs: 4000
Size of block after realloc of 1000 more longs: 8000

Memory Allocation Routines

See Also calloc, free, malloc


remove, _wremove

Delete a file.

int remove( const char *path );

int _wremove( const wchar_t *path );

Routine | Required Header | Compatibility
remove | <stdio.h> or <io.h> | ANSI, Win 95, Win NT
_wremove | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if the file is successfully deleted. Otherwise, it returns –1 and sets errno either to EACCES to indicate that the path specifies a read-only file, or to ENOENT to indicate that the filename or path was not found or that the path specifies a directory. This function fails and returns -1 if the file is open.

Parameter

path

Path of file to be removed

Remarks

The remove function deletes the file specified by path. _wremove is a wide-character version of _remove; the path argument to _wremove is a wide-character string. _wremove and _remove behave identically otherwise. All handles to a file must be closed before it can be deleted.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tremove | remove | remove | _wremove

Example

/* REMOVE.C: This program uses remove to delete REMOVE.OBJ. */

#include <stdio.h>

void main( void )
{
   if( remove( "remove.obj" ) == -1 )
      perror( "Could not delete 'REMOVE.OBJ'" );
   else
      printf( "Deleted 'REMOVE.OBJ'\n" );
}

Output

Deleted 'REMOVE.OBJ'

File Handling Routines

See Also _unlink


rename, _wrename

Rename a file or directory.

int rename( const char *oldname, const char *newname );

int _wrename( const wchar_t *oldname, const wchar_t *newname );

Routine | Required Header | Compatibility
rename | <io.h> or <stdio.h> | ANSI, Win 95, Win NT
_wrename | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if it is successful. On an error, the function returns a nonzero value and sets errno to one of the following values:

EACCES

File or directory specified by newname already exists or could not be created (invalid path); or oldname is a directory and newname specifies a different path.

ENOENT

File or path specified by oldname not found.

EINVAL

Name contains invalid characters.

For other possible return values, see _doserrno, _errno, syserrlist, and _sys_nerr.

Parameters

oldname

Pointer to old name

newname

Pointer to new name

Remarks

The rename function renames the file or directory specified by oldname to the name given by newname. The old name must be the path of an existing file or directory. The new name must not be the name of an existing file or directory. You can use rename to move a file from one directory or device to another by giving a different path in the newname argument. However, you cannot use rename to move a directory. Directories can be renamed, but not moved.

_wrename is a wide-character version of _rename; the arguments to _wrename are wide-character strings. _wrename and _rename behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_trename | rename | rename | _wrename

Example

/* RENAMER.C: This program attempts to rename a file
 * named RENAMER.OBJ to RENAMER.JBO. For this operation
 * to succeed, a file named RENAMER.OBJ must exist and
 * a file named RENAMER.JBO must not exist.
 */

#include <stdio.h>

void main( void )
{
   int  result;
   char old[] = "RENAMER.OBJ", new[] = "RENAMER.JBO";

   /* Attempt to rename file: */
   result = rename( old, new );
   if( result != 0 )
      printf( "Could not rename '%s'\n", old );
   else
      printf( "File '%s' renamed to '%s'\n", old, new );
}

Output

File 'RENAMER.OBJ' renamed to 'RENAMER.JBO'

File Handling Routines


rewind

Repositions the file pointer to the beginning of a file.

void rewind( FILE *stream );

Routine | Required Header | Compatibility
rewind | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

stream

Pointer to FILE structure

Remarks

The rewind function repositions the file pointer associated with stream to the beginning of the file. A call to rewind is similar to

(void) fseek( stream, 0L, SEEK_SET );

However, unlike fseek, rewind clears the error indicators for the stream as well as the end-of-file indicator. Also, unlike fseek, rewind does not return a value to indicate whether the pointer was successfully moved.

To clear the keyboard buffer, use rewind with the stream stdin, which is associated with the keyboard by default.

Example

/* REWIND.C: This program first opens a file named
 * REWIND.OUT for input and output and writes two
 * integers to the file. Next, it uses rewind to
 * reposition the file pointer to the beginning of
 * the file and reads the data back in.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   int data1, data2;

   data1 = 1;
   data2 = -37;

   if( (stream = fopen( "rewind.out", "w+" )) != NULL )
   {
      fprintf( stream, "%d %d", data1, data2 );
      printf( "The values written are: %d and %d\n", data1, data2 );
      rewind( stream );
      fscanf( stream, "%d %d", &data1, &data2 );
      printf( "The values read are: %d and %d\n", data1, data2 );
      fclose( stream );
   }
}

Output

The values written are: 1 and -37
The values read are: 1 and -37

Stream I/O Routines


_rmdir, _wrmdir

Delete a directory.

int _rmdir( const char *dirname );

int _wrmdir( const wchar_t *dirname );

Routine | Required Header | Compatibility
_rmdir | <direct.h> | Win 95, Win NT
_wrmdir | <direct.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if the directory is successfully deleted. A return value of –1 indicates an error, and errno is set to one of the following values:

ENOTEMPTY

Given path is not a directory; directory is not empty; or directory is either current working directory or root directory.

ENOENT

Path is invalid.

Parameter

dirname

Path of directory to be removed

Remarks

The _rmdir function deletes the directory specified by dirname. The directory must be empty, and it must not be the current working directory or the root directory.

_wrmdir is a wide-character version of _rmdir; the dirname argument to _wrmdir is a wide-character string. _wrmdir and _rmdir behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_trmdir | _rmdir | _rmdir | _wrmdir

Example

/* MAKEDIR.C */

#include <direct.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   if( _mkdir( "\\testtmp" ) == 0 )
   {
      printf( "Directory '\\testtmp' was successfully created\n" );
      system( "dir \\testtmp" );
      if( _rmdir( "\\testtmp" ) == 0 )
        printf( "Directory '\\testtmp' was successfully removed\n"  );
      else
         printf( "Problem removing directory '\\testtmp'\n" );
   }
   else
      printf( "Problem creating directory '\\testtmp'\n" );
}

Output

Directory '\testtmp' was successfully created
 Volume in drive C is CDRIVE
 Volume Serial Number is 0E17-1702

 Directory of C:\testtmp

05/03/94  12:30p        <DIR>           .
05/03/94  12:30p        <DIR>           ..
               2 File(s)          0 bytes
                             17,358,848 bytes free
Directory '\testtmp' was successfully removed

Directory Control Routines

See Also _chdir, _mkdir


_rmtmp

Removes temporary files.

int _rmtmp( void );

Routine | Required Header | Compatibility
_rmtmp | <stdio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_rmtmp returns the number of temporary files closed and deleted.

Remarks

The _rmtmp function cleans up all temporary files in the current directory. The function removes only those files created by tmpfile; use it only in the same directory in which the temporary files were created.

Example

/* TMPFILE.C: This program uses tmpfile to create a
 * temporary file, then deletes this file with _rmtmp.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char tempstring[] = "String to be written";
   int  i;

   /* Create temporary files. */
   for( i = 1; i <= 3; i++ )
   {
      if( (stream = tmpfile()) == NULL )
         perror( "Could not open new temporary file\n" );
      else
         printf( "Temporary file %d was created\n", i );
   }

   /* Remove temporary files. */
   printf( "%d temporary files deleted\n", _rmtmp() );
}

Output

Temporary file 1 was created
Temporary file 2 was created
Temporary file 3 was created
3 temporary files deleted

Stream I/O Routines

See Also _flushall, tmpfile, tmpnam


_rotl, _rotr

Rotate bits to the left (_rotl) or right (_rotr).

unsigned int _rotl( unsigned int value, int shift );

unsigned int _rotr( unsigned int value, int shift );

Routine | Required Header | Compatibility
_rotl | <stdlib.h> | Win 95, Win NT
_rotr | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Both functions return the rotated value. There is no error return.

Parameters

value

Value to be rotated

shift

Number of bits to shift

Remarks

The _rotl and _rotr functions rotate the unsigned value by shift bits. _rotl rotates the value left. _rotr rotates the value right. Both functions “wrap” bits rotated off one end of value to the other end.

Example

/* ROT.C: This program uses _rotr and _rotl with
 * different shift values to rotate an integer.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   unsigned val = 0x0fd93;
   printf( "0x%4.4x rotated left three times is 0x%4.4x\n",
           val, _rotl( val, 3 ) );
   printf( "0x%4.4x rotated right four times is 0x%4.4x\n",
           val, _rotr( val, 4 ) );
}

Output

0xfd93 rotated left three times is 0x7ec98
0xfd93 rotated right four times is 0x30000fd9

Floating-Point Support Routines

See Also _lrotl


_scalb

Scales argument by a power of 2.

double _scalb( double x, long exp );

Routine | Required Header | Compatibility
_scalb | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_scalb returns an exponential value if successful. On overflow (depending on the sign of x), _scalb returns +/– HUGE_VAL; the errno variable is set to ERANGE.

Parameters

x

Double-precision floating-point value

exp

Long integer exponent

Remarks

The _scalb function calculates the value of x * 2exp.

Floating-Point Support

See Also ldexp


scanf, wscanf

Read formatted data from the standard input stream.

int scanf( const char *format [,argument]... );

int wscanf( const wchar_t *format [,argument]... );

Routine | Required Header | Compatibility
scanf | <stdio.h> | ANSI, Win 95, Win NT
wscanf | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Both scanf and wscanf return the number of fields successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. The return value is EOF for an error or if the end-of-file character or the end-of-string character is encountered in the first attempt to read a character.

Parameters

format

Format control string

argument

Optional arguments

Remarks

The scanf function reads data from the standard input stream stdin and writes the data into the location given by argument. Each argument must be a pointer to a variable of a type that corresponds to a type specifier in format. If copying takes place between strings that overlap, the behavior is undefined.

wscanf is a wide-character version of scanf; the format argument to wscanf is a wide-character string. wscanf and scanf behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tscanf | scanf | scanf | wscanf

For more information, see Format Specification Fields — scanf functions and wscanf Functions.

Example

 /* SCANF.C: This program uses the scanf and wscanf functions
  * to read formatted input.
  */

#include <stdio.h>

void main( void )
{
   int   i, result;
   float fp;
   char  c, s[81];
   wchar_t wc, ws[81];

   printf( "\n\nEnter an int, a float, two chars and two strings\n");

   result = scanf( "%d %f %c %C %s %S", &i, &fp, &c, &wc, s, ws );
   printf( "\nThe number of fields input is %d\n", result );
   printf( "The contents are: %d %f %c %C %s %S\n", i, fp, c, wc, s, ws);

   wprintf( L"\n\nEnter an int, a float, two chars and two strings\n");

   result = wscanf( L"%d %f %hc %lc %S %ls", &i, &fp, &c, &wc, s, ws );
   wprintf( L"\nThe number of fields input is %d\n", result );
   wprintf( L"The contents are: %d %f %C %c %hs %s\n", i, fp, c, wc, s, ws);
}

Output

Enter an int, a float, two chars and two strings
71
98.6
h
z
Byte characters

The number of fields input is 6
The contents are: 71 98.599998 h z Byte characters

Enter an int, a float, two chars and two strings
36
92.3
y
n
Wide characters

The number of fields input is 6
The contents are: 456 92.300003 y n Wide characters

Floating-Point Support Routines, Stream I/O Routines, Locale Routines

See Also fscanf, printf, sprintf, sscanf


Format Specification Fields: scanf and wscanf Functions

A format specification has the following form:

%[*] [width] [{h | l | I64 | L}]type

The format argument specifies the interpretation of the input and can contain one or more of the following:

  • White-space characters: blank (' '); tab ('\t'); or newline ('\n'). A white-space character causes scanf to read, but not store, all consecutive white-space characters in the input up to the next non–white-space character. One white-space character in the format matches any number (including 0) and combination of white-space characters in the input.

  • Non–white-space characters, except for the percent sign (%). A non–white-space character causes scanf to read, but not store, a matching non–white-space character. If the next character in stdin does not match, scanf terminates.

  • Format specifications, introduced by the percent sign (%). A format specification causes scanf to read and convert characters in the input into values of a specified type. The value is assigned to an argument in the argument list.

The format is read from left to right. Characters outside format specifications are expected to match the sequence of characters in stdin; the matching characters in stdin are scanned but not stored. If a character in stdin conflicts with the format specification, scanf terminates, and the character is left in stdin as if it had not been read.

When the first format specification is encountered, the value of the first input field is converted according to this specification and stored in the location that is specified by the first argument. The second format specification causes the second input field to be converted and stored in the second argument, and so on through the end of the format string.

An input field is defined as all characters up to the first white-space character (space, tab, or newline), or up to the first character that cannot be converted according to the format specification, or until the field width (if specified) is reached. If there are too many arguments for the given specifications, the extra arguments are evaluated but ignored. The results are unpredictable if there are not enough arguments for the format specification.

Each field of the format specification is a single character or a number signifying a particular format option. The type character, which appears after the last optional format field, determines whether the input field is interpreted as a character, a string, or a number.

The simplest format specification contains only the percent sign and a type character (for example, %s). If a percent sign (%) is followed by a character that has no meaning as a format-control character, that character and the following characters (up to the next percent sign) are treated as an ordinary sequence of characters, that is, a sequence of characters that must match the input. For example, to specify that a percent-sign character is to be input, use %%.

An asterisk (*) following the percent sign suppresses assignment of the next input field, which is interpreted as a field of the specified type. The field is scanned but not stored.


scanf Width Specification

width is a positive decimal integer controlling the maximum number of characters to be read from stdin. No more than width characters are converted and stored at the corresponding argument. Fewer than width characters may be read if a white-space character (space, tab, or newline) or a character that cannot be converted according to the given format occurs before width is reached.

The optional prefixes h, l, I64, and L indicate the “size” of the argument (long or short, single-byte character or wide character, depending upon the type character that they modify). These format-specification characters are used with type characters in scanf or wscanf functions to specify interpretation of arguments as shown in the Table R.7. The type prefixes h, l, I64, and L are Microsoft extensions and are not ANSI-compatible. The type characters and their meanings are described in Table R.8.

Table R.7 Size Prefixes for scanf and wscanf Format-Type Specifiers

To Specify | Use Prefix | With Type Specifier
double | l | e, E, f, g, or G
long int | l | d, i, o, x, or X
long unsigned int | l | u
short int | h | d, i, o, x, or X
short unsigned int | h | u
__int64 | I64 | d, i, o, u, x, or X
Single-byte character with scanf | h | c or C
Single-byte character with wscanf | h | c or C
Wide character with scanf | l | c or C
Wide character with wscanf | l | c, or C
Single-byte – character string with scanf | h | s or S
Single-byte – character string with wscanf | h | s or S
Wide-character string with scanf | l | s or S
Wide-character string with wscanf | l | s or S

Following are examples of the use of h and l with scanffunctions and wscanf functions:

scanf( "%ls", &x );    // Read a wide-character string
wscanf( "%lC", &x );    // Read a single-byte character

To read strings not delimited by space characters, a set of characters in brackets ([ ]) can be substituted for the s (string) type character. The corresponding input field is read up to the first character that does not appear in the bracketed character set. If the first character in the set is a caret (^), the effect is reversed: The input field is read up to the first character that does appear in the rest of the character set.

Note that %[a-z] and %[z-a] are interpreted as equivalent to %[abcde...z]. This is a common scanf function extension, but note that the ANSI standard does not require it.

To store a string without storing a terminating null character ('\0'), use the specification %n c where n is a decimal integer. In this case, the c type character indicates that the argument is a pointer to a character array. The next n characters are read from the input stream into the specified location, and no null character ('\0') is appended. If n is not specified, its default value is 1.

The scanf function scans each input field, character by character. It may stop reading a particular input field before it reaches a space character for a variety of reasons:

  • The specified width has been reached.

  • The next character cannot be converted as specified.

  • The next character conflicts with a character in the control string that it is supposed to match.

  • The next character fails to appear in a given character set.

For whatever reason, when the scanf function stops reading an input field, the next input field is considered to begin at the first unread character. The conflicting character, if there is one, is considered unread and is the first character of the next input field or the first character in subsequent read operations on stdin.


scanf Type Field Characters

The type character is the only required format field; it appears after any optional format fields. The type character determines whether the associated argument is interpreted as a character, string, or number.

Table R.8 Type Characters for scanf functions

Character | Type of Input Expected | Type of Argument
c | When used with scanf functions, specifies single-byte character; when used with wscanf functions, specifies wide character. White-space characters that are ordinarily skipped are read when c is specified. To read next non–white-space single-byte character, use %1s; to read next non–white-space wide character, use %1ws. | Pointer to char when used with scanf functions, pointer to wchar_t when used with wscanf functions.
C | When used with scanf functions, specifies wide character; when used with wscanf functions, specifies single-byte character. White-space characters that are ordinarily skipped are read when C is specified. To read next non–white-space single-byte character, use %1s; to read next non–white-space wide character, use %1ws. | Pointer to wchar_t when used with scanf functions, pointer to char when used with wscanf functions.
d | Decimal integer. | Pointer to int.
i | Decimal, hexadecimal, or octal integer. | Pointer to int.
o | Octal integer. | Pointer to int.
u | Unsigned decimal integer. | Pointer to unsigned int.
x | Hexadecimal integer. | Pointer to int.
e, E, f, g, G | Floating-point value consisting of optional sign (+ or –), series of one or more decimal digits containing decimal point, and optional exponent (“e” or “E”) followed by an optionally signed integer value. | Pointer to float.
n | No input read from stream or buffer. | Pointer to int, into which is stored number of characters successfully read from stream or buffer up to that point in current call to scanf functions or wscanf functions.
s | String, up to first white-space character (space, tab or newline). To read strings not delimited by space characters, use set of square brackets ([ ]), as discussed following Table R.7. | When used with scanf functions, signifies single-byte character array; when used with wscanf functions, signifies wide-character array. In either case, character array must be large enough for input field plus terminating null character, which is automatically appended.
S | String, up to first white-space character (space, tab or newline). To read strings not delimited by space characters, use set of square brackets ([ ]), as discussed preceding this table. | When used with scanf functions, signifies wide-character array; when used with wscanf functions, signifies single-byte–character array. In either case, character array must be large enough for input field plus terminating null character, which is automatically appended.

The types c, C, s, and S are Microsoft extensions and are not ANSI-compatible.

Thus, to read single-byte or wide characters with scanf functions and wscanf functions, use format specifiers as follows.

To Read Character As | Use This Function | With These Format Specifiers
single byte | scanf functions | c, hc, or hC
single byte | wscanf functions | C, hc, or hC
wide | wscanf functions | c, lc, or lC
wide | scanf functions | C, lc, or lC

To scan strings with scanf functions, and wscanf functions, use the prefixes h and l analogously with format type-specifiers s and S.


_searchenv, _wsearchenv

Searches for a file using environment paths.

void _searchenv( const char *filename, const char *varname, char *pathname );

void _wsearchenv( const wchar_t *filename, const wchar_t *varname, wchar_t *pathname );

Routine | Required Header | Compatibility
_searchenv | <stdlib.h> | Win 95, Win NT
_wsearchenv | <stdlib.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

filename

Name of file to search for

varname

Environment to search

pathname

Buffer to store complete path

Remarks

The _searchenv routine searches for the target file in the specified domain. The varname variable can be any environment or user-defined variable that specifies a list of directory paths, such as PATH, LIB, and INCLUDE._searchenv is case sensitive, so varname should match the case of the environment variable.

The routine searches first for the file in the current working directory. If it does not find the file, it looks next through the directories specified by the environment variable. If the target file is in one of those directories, the newly created path is copied into pathname. If the filename file is not found, pathname contains an empty, null-terminated string.

The pathname buffer must be large enough to accomodate the full length of the constructed path name. Otherwise, _searchenv will overwite the pathname buffer resulting in unexpected behavior. This condition can be avoided by ensuring that the length of the constructed path name does not exceed the size of the pathname buffer, by calculating the maximum sum of the filename and varname lengths before calling _searchenv.

_wsearchenv is a wide-character version of _searchenv; the arguments to _wsearchenv are wide-character strings. _wsearchenv and _searchenv behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tsearchenv | _searchenv | _searchenv | _wsearchenv

Example

/* SEARCHEN.C: This program searches for a file in
 * a directory specified by an environment variable.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char pathbuffer[_MAX_PATH];
   char searchfile[] = "CL.EXE";
   char envvar[] = "PATH";

   /* Search for file in PATH environment variable: */
   _searchenv( searchfile, envvar, pathbuffer );
   if( *pathbuffer != '\0' )
      printf( "Path for %s: %s\n", searchfile, pathbuffer );
   else
      printf( "%s not found\n", searchfile );
}

Output

Path for CL.EXE: C:\msvcnt\c32\bin\CL.EXE

Directory Control Routines

See Also getenv, _putenv


setbuf

Controls stream buffering.

void setbuf( FILE *stream, char *buffer );

Routine | Required Header | Compatibility
setbuf | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

stream

Pointer to FILE structure

buffer

User-allocated buffer

Remarks

The setbuf function controls buffering for stream. The stream argument must refer to an open file that has not been read or written. If the buffer argument is NULL, the stream is unbuffered. If not, the buffer must point to a character array of length BUFSIZ, where BUFSIZ is the buffer size as defined in STDIO.H. The user-specified buffer, instead of the default system-allocated buffer for the given stream, is used for I/O buffering. The stderr stream is unbuffered by default, but you can use setbuf to assign buffers to stderr.

setbuf has been replaced by setvbuf, which is the preferred routine for new code. setbuf is retained for compatibility with existing code.

Example

/* SETBUF.C: This program first opens files named DATA1 and
 * DATA2. Then it uses setbuf to give DATA1 a user-assigned
 * buffer and to change DATA2 so that it has no buffer.
 */

#include <stdio.h>

void main( void )
{
   char buf[BUFSIZ];
   FILE *stream1, *stream2;

   if( ((stream1 = fopen( "data1", "a" )) != NULL) &&
       ((stream2 = fopen( "data2", "w" )) != NULL) )
   {
      /* "stream1" uses user-assigned buffer: */
      setbuf( stream1, buf );
      printf( "stream1 set to user-defined buffer at: %Fp\n", buf );

      /* "stream2" is unbuffered              */
      setbuf( stream2, NULL );
      printf( "stream2 buffering disabled\n" );
      _fcloseall();
   }
}

Output

stream1 set to user-defined buffer at: 0013FDA0
stream2 buffering disabled

Stream I/O Routines

See Also fclose, fflush, fopen, setvbuf


setjmp

Saves the current state of the program.

int setjmp( jmp_buf env );

Routine | Required Header | Compatibility
setjmp | <setjmp.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

setjmp returns 0 after saving the stack environment. If setjmp returns as a result of a longjmp call, it returns the value argument of longjmp, or if the value argument of longjmp is 0, setjmp returns 1. There is no error return.

Parameter

env

Variable in which environment is stored

Remarks

The setjmp function saves a stack environment, which you can subsequently restore using longjmp. When used together, setjmp and longjmp provide a way to execute a “non-local goto.” They are typically used to pass execution control to error-handling or recovery code in a previously called routine without using the normal calling or return conventions.

A call to setjmp saves the current stack environment in env. A subsequent call to longjmp restores the saved environment and returns control to the point just after the corresponding setjmp call. All variables (except register variables) accessible to the routine receiving control contain the values they had when longjmp was called.

setjmp and longjmp do not support C++ object semantics. In C++ programs, use the C++ exception-handling mechanism.

Example

/* FPRESET.C: This program uses signal to set up a
 * routine for handling floating-point errors.
 */

#include <stdio.h>
#include <signal.h>
#include <setjmp.h>
#include <stdlib.h>
#include <float.h>
#include <math.h>
#include <string.h>

jmp_buf mark;              /* Address for long jump to jump to */
int     fperr;             /* Global error number */

void __cdecl fphandler( int sig, int num );   /* Prototypes */
void fpcheck( void );

void main( void )
{
   double n1, n2, r;
   int jmpret;
   /* Unmask all floating-point exceptions. */
    _control87( 0, _MCW_EM );
   /* Set up floating-point error handler. The compiler
    * will generate a warning because it expects
    * signal-handling functions to take only one argument.
    */
    if( signal( SIGFPE, fphandler ) == SIG_ERR )

   {
      fprintf( stderr, "Couldn't set SIGFPE\n" );
      abort();   }

   /* Save stack environment for return in case of error. First
    * time through, jmpret is 0, so true conditional is executed.
    * If an error occurs, jmpret will be set to -1 and false
    * conditional will be executed.
    */
   jmpret = setjmp( mark );
   if( jmpret == 0 )
   {
      printf( "Test for invalid operation - " );
      printf( "enter two numbers: " );
      scanf( "%lf %lf", &n1, &n2 );
      r = n1 / n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g / %4.3g = %4.3g\n", n1, n2, r );

      r = n1 * n2;
      /* This won't be reached if error occurs. */
      printf( "\n\n%4.3g * %4.3g = %4.3g\n", n1, n2, r );
   }
   else
      fpcheck();
}
/* fphandler handles SIGFPE (floating-point error) interrupt. Note
 * that this prototype accepts two arguments and that the
 * prototype for signal in the run-time library expects a signal
 * handler to have only one argument.
 *
 * The second argument in this signal handler allows processing of
 * _FPE_INVALID, _FPE_OVERFLOW, _FPE_UNDERFLOW, and
 * _FPE_ZERODIVIDE, all of which are Microsoft-specific symbols
 * that augment the information provided by SIGFPE. The compiler
 * will generate a warning, which is harmless and expected.

 */
void fphandler( int sig, int num )
{
   /* Set global for outside check since we don't want
    * to do I/O in the handler.
    */
   fperr = num;
   /* Initialize floating-point package. */
   _fpreset();
   /* Restore calling environment and jump back to setjmp. Return
    * -1 so that setjmp will return false for conditional test.
    */
   longjmp( mark, -1 );
}
void fpcheck( void )
{
   char fpstr[30];
   switch( fperr )
   {
   case _FPE_INVALID:
       strcpy( fpstr, "Invalid number" );
       break;
   case _FPE_OVERFLOW:
       strcpy( fpstr, "Overflow" );

       break;
   case _FPE_UNDERFLOW:
       strcpy( fpstr, "Underflow" );
       break;
   case _FPE_ZERODIVIDE:
       strcpy( fpstr, "Divide by zero" );
       break;
   default:
       strcpy( fpstr, "Other floating point error" );
       break;
   }
   printf( "Error %d: %s\n", fperr, fpstr );
}

Output

Test for invalid operation - enter two numbers: 5 0
Error 131: Divide by zero

Process and Environment Control Routines

See Also longjmp


setlocale, _wsetlocale

Define the locale.

char *setlocale( int category, const char *locale );

wchar_t *_wsetlocale( int category, const wchar_t *locale );

Routine | Required Header | Compatibility
setlocale | <locale.h> | ANSI, Win 95, Win NT
_wsetlocale | <locale.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If a valid locale and category are given, the function returns a pointer to the string associated with the specified locale and category. If the locale or category is invalid, the function returns a null pointer and the current locale settings of the program are not changed.

For example, the call

setlocale( LC_ALL, "English" );

sets all categories, returning only the string English_USA.1252. If all categories are not explicitly set by a call to setlocale, the function returns a string indicating the current setting of each of the categories, separated by semicolons. If the locale argument is a null pointer, setlocale returns a pointer to the string associated with the category of the program’s locale; the program’s current locale setting is not changed.

The null pointer is a special directive that tells setlocale to query rather than set the international environment. For example, the sequence of calls

// Set all categories and return "English_USA.1252"
setlocale( LC_ALL, "English" );
// Set only the LC_MONETARY category and return "French_France.1252"
setlocale( LC_MONETARY, "French" );
setlocale( LC_ALL, NULL );

returns

LC_COLLATE=English_USA.1252;
LC_CTYPE=English_USA.1252;
LC_MONETARY=French_France.1252;
LC_NUMERIC=English_USA.1252;
LC_TIME=English_USA.1252

which is the string associated with the LC_ALL category.

You can use the string pointer returned by setlocale in subsequent calls to restore that part of the program’s locale information, assuming that your program does not alter the pointer or the string. Later calls to setlocale overwrite the string; you can use _strdup to save a specific locale string.

Parameters

category

Category affected by locale

locale

Locale name

Remarks

Use the setlocale function to set, change, or query some or all of the current program locale information specified by locale and category. “Locale” refers to the locality (country and language) for which you can customize certain aspects of your program. Some locale-dependent categories include the formatting of dates and the display format for monetary values.

_wsetlocale is a wide-character version of setlocale; the locale argument and return value of _wsetlocale are wide-character strings. _wsetlocale and setlocale behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tsetlocale | setlocale | setlocale | _wsetlocale

The category argument specifies the parts of a program’s locale information that are affected. The macros used for category and the parts of the program they affect are as follows:

LC_ALL

All categories, as listed below

LC_COLLATE

The strcoll, _stricoll, wcscoll, _wcsicoll, and strxfrm functions

LC_CTYPE

The character-handling functions (except isdigit, isxdigit, mbstowcs, and mbtowc, which are unaffected)

LC_MONETARY

Monetary-formatting information returned by the localeconv function

LC_NUMERIC

Decimal-point character for the formatted output routines (such as printf), for the data-conversion routines, and for the nonmonetary-formatting information returned by localeconv

LC_TIME

The strftime and wcsftime functions

The locale argument is a pointer to a string that specifies the name of the locale. If locale points to an empty string, the locale is the implementation-defined native environment. A value of “C” specifies the minimal ANSI conforming environment for C translation. The “C” locale assumes that all char data types are 1 byte and that their value is always less than 256. The “C” locale is the only locale supported in Microsoft Visual C++ version 1.0 and earlier versions of Microsoft C/C++. Microsoft Visual C++ supports all the locales listed in Appendix A, Language and Country Strings. At program startup, the equivalent of the following statement is executed:

setlocale( LC_ALL, "C" );

The locale argument takes the following form:

locale :: "lang[_country[.code_page]]"
            | ".code_page"
            | ""
            | NULL

The set of available languages, countries, and code pages includes all those supported by the Win32 NLS API. The set of language and country codes supported by setlocale is listed in Appendix A, Language and Country Strings.

If locale is a null pointer, setlocale queries, rather than sets, the international environment, and returns a pointer to the string associated with the specified category. The program’s current locale setting is not changed. For example,

setlocale( LC_ALL, NULL );

returns the string associated with category.

The following examples pertain to the LC_ALL category. Either of the strings ".OCP" and ".ACP" can be used in place of a code page number to specify use of the system default OEM code page and system-default ANSI code page, respectively.

setlocale( LC_ALL, "" );

Sets the locale to the default, which is the system-default ANSI code page obtained from the operating system.

setlocale( LC_ALL, ".OCP" );

Explicitly sets the locale to the current OEM code page obtained from the operating system.

setlocale( LC_ALL, ".ACP" );

Sets the locale to the ANSI code page obtained from the operating system.

setlocale( LC_ALL, "[lang_ctry]" );

Sets the locale to the language and country indicated, using the default code page obtained from the host operating system.

setlocale( LC_ALL, "[lang_ctry.cp]" );

Sets the locale to the language, country, and code page indicated in the [lang_ctry.cp] string. You can use various combinations of language, country, and code page. For example:

setlocale( LC_ALL, "French_Canada.1252" );
// Set code page to French Canada ANSI default
setlocale( LC_ALL, "French_Canada.ACP" );
// Set code page to French Canada OEM default
setlocale( LC_ALL, "French_Canada.OCP" );

setlocale( LC_ALL, "[lang]" );

Sets the locale to the country indicated, using the default country for the language specified, and the system-default ANSI code page for that country as obtained from the host operating system. For example, the following two calls to setlocale are functionally equivalent:

setlocale( LC_ALL, "English" );
setlocale( LC_ALL, "English_United States.1252" );

setlocale( LC_ALL, "[.code_page]" );

Sets the code page to the value indicated, using the default country and language (as defined by the host operating system) for the specified code page.

The category must be either LC_ALL or LC_CTYPE to effect a change of code page. For example, if the default country and language of the host operating system are “United States” and “English,” the following two calls to setlocale are functionally equivalent:

setlocale( LC_ALL, ".1252" );
setlocale( LC_ALL, "English_United States.1252");

For more information see the setlocale pragma in Preprocessor Reference.

Example

/* LOCALE.C: Sets the current locale to "Germany" using the
 * setlocale function and demonstrates its effect on the strftime
 * function.
 */

#include <stdio.h>
#include <locale.h>
#include <time.h>

void main(void)
{
       time_t ltime;
       struct tm *thetime;
       unsigned char str[100];

       setlocale(LC_ALL, "German");
       time (&ltime);
       thetime = gmtime(&ltime);

       /* %#x is the long date representation, appropriate to
        * the current locale
        */
       if (!strftime((char *)str, 100, "%#x",
                     (const struct tm *)thetime))
               printf("strftime failed!\n");
       else
               printf("In German locale, strftime returns '%s'\n",
                      str);

       /* Set the locale back to the default environment */
       setlocale(LC_ALL, "C");
       time (&ltime);
       thetime = gmtime(&ltime);

       if (!strftime((char *)str, 100, "%#x",
                     (const struct tm *)thetime))
               printf("strftime failed!\n");
       else
               printf("In 'C' locale, strftime returns '%s'\n",
                      str);
}

Output

In German locale, strftime returns 'Donnerstag, 22. April 1993'
In 'C' locale, strftime returns 'Thursday, April 22, 1993'

Locale Routines

See Also localeconv, mblen, _mbstrlen, mbstowcs, mbtowc, strcoll Functions, strftime, strxfrm, wcstombs, wctomb


_setmaxstdio

Sets a maximum for the number of simultaneously open files at the stdio level.

int _setmaxstdio( int newmax );

Routine | Required Header | Compatibility
_setmaxstdio | <stdio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Returns newmax if successful; –1 otherwise.

Parameter

newmax

New maximum for number of simultaneously open files at the stdio level

Remarks

The _setmaxstdio function changes the maximum value for the number of files which may be simultaneously open at the stdio level.

C run-time I/O now supports many more open files on Win32 platforms than in previous versions. Up to 2,048 files may be open simultaneously at the lowio level (that is, opened and accessed by means of the _open, _read, _write, and so forth family of I/O functions). Up to 512 files may be open simultaneously at the stdio level (that is, opened and accessed by means of the fopen, fgetc, fputc, and so forth family of functions). The limit of 512 open files at the stdio level may be increased to a maximum of 2,048 by means of the _setmaxstdio function.

Since stdio level functions, such as fopen, are built on top of the lowio functions, the maximum of 2,048 is a hard upper limit for the number of simultaneously open files accessed through the C run-time library.

Note This upper limit may be beyond what is supported by a particular Win32 platform and configuration.

Stream I/O Routines


_setmbcp

Sets a new multibyte code page.

int _setmbcp( int codepage );

Routine | Required Header | Compatibility
_setmbcp | <mbctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_setmbcp returns 0 if the code page is set successfully. If an invalid code page value is supplied for codepage, the function returns –1 and the code page setting is unchanged.

Parameter

codepage

New code page setting for locale-independent multibyte routines

Remarks

The _setmbcp function specifies a new multibyte code page. By default, the run-time system automatically sets the multibyte code page to the system-default ANSI code page. The multibyte code page setting affects all multibyte routines that are not locale-dependent. However, it is possible to instruct _setmbcp to use the code page defined for the current locale (see the following list of manifest constants and associated behavior results). For a list of the multibyte routines that are dependent on the locale code page rather than the multibyte code page, see Interpretation of Multibyte-Character Sequences.

The multibyte code page also affects multibyte-character processing by the following run-time library routines:

_exec functions | _mktemp | _stat
_fullpath | _spawn functions | _tempnam
_makepath | _splitpath | tmpnam

In addition, all run-time library routines that receive multibyte-character argv or envp program arguments as parameters (such as the _exec and _spawn families) process these strings according to the multibyte code page. Hence these routines are also affected by a call to _setmbcp that changes the multibyte code page.

The codepage argument can be set to any of the following values:

  • _MB_CP_ANSI Use ANSI code page obtained from operating system at program startup

  • _MB_CP_LOCALE Use the current locale’s code page obtained from a previous call to setlocale

  • _MB_CP_OEM Use OEM code page obtained from operating system at program startup

  • _MB_CP_SBCS Use single-byte code page. When the code page is set to _MB_CP_SBCS, a routine such as _ismbblead always returns false.

  • Any other valid code page value, regardless of whether the value is an ANSI, OEM, or other operating-sytem – supported code page.

See Also _getmbcp, setlocale


_setmode

Sets the file translation mode.

int _setmode ( int handle, int mode );

Routine | Required Header | Optional Headers | Compatibility
_setmode | <io.h> | <fcntl.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _setmode returns the previous translation mode. A return value of –1 indicates an error, in which case errno is set to either EBADF, indicating an invalid file handle, or EINVAL, indicating an invalid mode argument (neither _O_TEXT nor _O_BINARY).

Parameters

handle

File handle

mode

New translation mode

Remarks

The _setmode function sets to mode the translation mode of the file given by handle. The mode must be one of two manifest constants, _O_TEXT or _O_BINARY. _O_TEXT sets text (translated) mode. Carriage return–linefeed (CR-LF) combinations are translated into a single linefeed character on input. Linefeed characters are translated into CR-LF combinations on output. _O_BINARY sets binary (untranslated) mode, in which these translations are suppressed.

_setmode is typically used to modify the default translation mode of stdin and stdout, but you can use it on any file. If you apply _setmode to the file handle for a stream, call _setmode before performing any input or output operations on the stream.

Example

/* SETMODE.C: This program uses _setmode to change
 * stdin from text mode to binary mode.
 */

#include <stdio.h>
#include <fcntl.h>
#include <io.h>

void main( void )
{
   int result;

   /* Set "stdin" to have binary mode: */
   result = _setmode( _fileno( stdin ), _O_BINARY );
   if( result == -1 )
      perror( "Cannot set mode" );
   else
      printf( "'stdin' successfully changed to binary mode\n" );
}

Output

'stdin' successfully changed to binary mode

File Handling Routines

See Also _creat, fopen, _open


_set_new_handler

Transfer control to your error-handling mechanism if the new operator fails to allocate memory.

_PNH _set_new_handler( _PNH pNewHandler );

Routine | Required Header | Compatibility
_set_new_handler | <new.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_set_new_handler returns a pointer to the previous exception handling function registered by _set_new_handler, so that the previous function can be restored later. If no previous function has been set, the return value may be used to restore the default behavior; this value may be NULL.

Parameter

pNewHandler

Pointer to the application-supplied memory handling function

Remarks

Call the C++ _set_new_handler function to specify an exception-handling function that is to gain control if the new operator fails to allocate memory. If new fails, the run-time system automatically calls the exception-handling function that was passed as an argument to _set_new_handler. _PNH, defined in NEW.H, is a pointer to a function that returns type int and takes an argument of type size_t. Use size_t to specify the amount of space to be allocated.

_set_new_handler is essentially a garbage-collection scheme. The run-time system retries allocation each time your function returns a nonzero value and fails if your function returns 0.

An occurrence of one of the _set_new_handler functions in a program registers the exception-handling function specified in the argument list with the run-time system:

#include <new.h>
int handle_program_memory_depletion( size_t )
{
   // Your code
}
void main( void )
{
   _set_new_handler( handle_program_memory_depletion );
   int *pi = new int[BIG_NUMBER];
}

You can save the function address that was last passed to the _set_new_handler function and reinstate it later:

_PNH old_handler = _set_new_handler( my_handler );
   // Code that requires my_handler
   _set_new_handler( old_handler )
   // Code that requires old_handler

The C++ _set_new_mode function sets the new handler mode for malloc. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when malloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. To override the default, call

_set_new_mode(1)

early in your program, or link with NEWMODE.OBJ.

For more information, see new and delete in the Language Quick Reference.

Example

/* HANDLER.CPP: This program uses _set_new_handler to
 * print an error message if the new operator fails.
 */

#include <stdio.h>
#include <new.h>

/* Allocate memory in chunks of size MemBlock. */
const size_t MemBlock = 1024;

/* Allocate a memory block for the printf function to use in case
 * of memory allocation failure; the printf function uses malloc.
 * The failsafe memory block must be visible globally because the
 * handle_program_memory_depletion function can take one
 * argument only.
 */
char * failsafe = new char[128];

/* Declare a customized function to handle memory-allocation failure.
 * Pass this function as an argument to _set_new_handler.
 */
int handle_program_memory_depletion( size_t );

void main( void )
{
   // Register existence of a new memory handler.
   _set_new_handler( handle_program_memory_depletion );
   size_t *pmemdump = new size_t[MemBlock];
   for( ; pmemdump != 0; pmemdump = new size_t[MemBlock] );
}

int handle_program_memory_depletion( size_t size )
{
   // Release character buffer memory.
   delete failsafe;
   printf( "Allocation failed, " );
   printf( "%u bytes not available.\n", size );
   // Tell new to stop allocation attempts.
   return 0;
}

Output

Allocation failed %0 bytes not available.

Memory Allocation Routines

See Also calloc, free, realloc


_set_new_mode

Sets a new handler mode for malloc.

int _set_new_mode( int newhandlermode );

Routine | Required Header | Compatibility
_set_new_mode | <new.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_set_new_mode returns the previous handler mode set for malloc. A return value of 1 indicates that, on failure to allocate memory, malloc previously called the new handler routine; a return value of 0 indicates that it did not. If the newhandlermode argument does not equal 0 or 1, _set_new_mode returns –1.

Parameter

newhandlermode

New handler mode for malloc; valid value is 0 or 1

Remarks

The C++ _set_new_mode function sets the new handler mode for malloc. The new handler mode indicates whether, on failure, malloc is to call the new handler routine as set by _set_new_handler. By default, malloc does not call the new handler routine on failure to allocate memory. You can override this default behavior so that, when malloc fails to allocate memory, malloc calls the new handler routine in the same way that the new operator does when it fails for the same reason. For more information, see the new and delete operators in the Language Quick Reference. To override the default, call

_set_new_mode(1)

early in your program, or link with NEWMODE.OBJ.

Memory Allocation Routines

See Also calloc, free, realloc, _query_new_handler, _query_new_mode


_set_sbh_threshold

Sets the upper limit for the size of a memory allocation that will be supported by the small-block heap.

int _set_sbh_threshold( size_t size );

Routine | Required Header | Compatibility
_set_sbh_threshold | <malloc.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_set_sbh_threshold returns 1 if the operation of setting the small-block threshold size is successful. It returns 0 if the input threshold size is too big.

Parameter

size the new small-block threshold size to be set

Remarks

This function takes a user specified small-block threshold size as input, and sets the current small-block threshold size to that value. The small-block heap threshold size can be set to any multiples of 16, from 0 to 1920 bytes for Windows 95 and all Windows NT platforms except the DEC Alpha, and from 0 to 3616 bytes for DEC Alpha platforms.

Memory Allocation Routines

See Also _get_sbh_thresold


_set_se_translator

Handles Win32 exceptions (C structured exceptions) as C++ typed exceptions.

typedef void (*_se_translator_function)( unsigned int, struct _EXCEPTION_POINTERS* );

_se_translator_function _set_se_translator( _se_translator_function se_trans_func );

Routine | Required Header | Compatibility
_set_se_translator | <eh.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_set_se_translator returns a pointer to the previous translator function registered by _set_se_translator, so that the previous function can be restored later. If no previous function has been set, the return value may be used to restore the default behavior; this value may be NULL.

Parameter

se_trans_func

Pointer to a C structured exception translator function that you write

Remarks

The _set_se_translator function provides a way to handle Win32 exceptions (C structured exceptions) as C++ typed exceptions. To allow each C exception to be handled by a C++ catch handler, first define a C exception “wrapper” class that can be used, or derived from, in order to attribute a specific class type to a C exception. To use this class, install a custom C exception translator function that is called by the internal exception-handling mechanism each time a C exception is raised. Within your translator function, you can throw any typed exception that can be caught by a matching C++ catch handler.

To specify a custom translation function, call _set_se_translator with the name of your translation function as its argument. The translator function that you write is called once for each function invocation on the stack that has try blocks. There is no default translator function.

In a multithreaded environment, translator functions are maintained separately for each thread. Each new thread needs to install its own translator function. Thus, each thread is in charge of its own translation handling.

The se_trans_func function that you write must take an unsigned integer and a pointer to a Win32 _EXCEPTION_POINTERS structure as arguments. The arguments are the return values of calls to the Win32 API GetExceptionCode and GetExceptionInformation functions, respectively.

Example

/*  SETRANS.CPP
 */

#include <stdio.h>
#include <windows.h>
#include <eh.h>

void SEFunc();
void trans_func( unsigned int, EXCEPTION_POINTERS* );

class SE_Exception
{
private:
    unsigned int nSE;
public:
    SE_Exception() {}
    SE_Exception( unsigned int n ) : nSE( n ) {}
    ~SE_Exception() {}
    unsigned int getSeNumber() { return nSE; }
};
void main( void )
{
    try
    {
        _set_se_translator( trans_func );
        SEFunc();
    }
    catch( SE_Exception e )
    {
        printf( "Caught a __try exception with SE_Exception.\n" );
    }
}
void SEFunc()
{
    __try
    {
        int x, y=0;
        x = 5 / y;
    }
    __finally
    {
        printf( "In finally\n" );
    }
}
void trans_func( unsigned int u, EXCEPTION_POINTERS* pExp )
{
    printf( "In trans_func.\n" );
    throw SE_Exception();
}

Output

In finally.
In trans_func.
Caught a __try exception with SE_Exception.

Exception Handling Routines

See Also set_terminate, set_unexpected, terminate, unexpected


set_terminate

Installs your own termination routine to be called by terminate.

typedef void (*terminate_function)();

terminate_function set_terminate( terminate_function term_func );

Routine | Required Header | Compatibility
set_terminate | <eh.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

set_terminate returns a pointer to the previous function registered by set_terminate, so that the previous function can be restored later. If no previous function has been set, the return value may be used to restore the default behavior; this value may be NULL.

Parameter

term_func

Pointer to a terminate function that you write

Remarks

The set_terminate function installs term_func as the function called by terminate. set_terminate is used with C++ exception handling and may be called at any point in your program before the exception is thrown. terminate calls abort by default. You can change this default by writing your own termination function and calling set_terminate with the name of your function as its argument. terminate calls the last function given as an argument to set_terminate. After performing any desired cleanup tasks, term_func should exit the program. If it does not exit (if it returns to its caller), abort is called.

In a multithreaded environment, terminate functions are maintained separately for each thread. Each new thread needs to install its own terminate function. Thus, each thread is in charge of its own termination handling.

The terminate_function type is defined in EH.H as a pointer to a user-defined termination function, term_func, that returns void. Your custom function term_func can take no arguments and should not return to its caller. If it does, abort is called. An exception may not be thrown from within term_func.

Note The set_terminate function only works outside the debugger.

Example

/* TERMINAT.CPP:
 */
#include <eh.h>
#include <process.h>
#include <iostream.h>

void term_func();

void main()
{

    int i = 10, j = 0, result;
    set_terminate( term_func );
    try
    {
        if( j == 0 )
            throw "Divide by zero!";
        else
            result = i/j;

    }
    catch( int )
    {
        cout << "Caught some integer exception.\n";
    }
    cout << "This should never print.\n";

}
void term_func()
{
    cout << "term_func() was called by terminate().\n";

    // ... cleanup tasks performed here

    // If this function does not exit, abort is called.

    exit(-1);
}

Output

term_func() was called by terminate().

Exception Handling Routines

See Also abort, set_unexpected, terminate, unexpected


set_unexpected

Installs your own termination function to be called by unexpected.

typedef void (*unexpected_function)();

unexpected_function set_unexpected( unexpected_function unexp_func );

Routine | Required Header | Compatibility
set_unexpected | <eh.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_set_unexpected returns a pointer to the previous termination function registered by _set_unexpected, so that the previous function can be restored later. If no previous function has been set, the return value may be used to restore the default behavior; this value may be NULL.

Parameter

unexp_func

Pointer to a function that you write to replace the unexpected function

Remarks

The set_unexpected function installs unexp_func as the function called by unexpected. unexpected is not used in the current C++ exception-handling implementation. The unexpected_function type is defined in EH.H as a pointer to a user-defined unexpected function, unexp_func, that returns void. Your custom unexp_func function should not return to its caller.

By default, unexpected calls terminate. You can change this default behavior by writing your own termination function and calling set_unexpected with the name of your function as its argument. unexpected calls the last function given as an argument to set_unexpected.

Unlike the custom termination function installed by a call to set_terminate, an exception can be thrown from within unexp_func.

In a multithreaded environment, unexpected functions are maintained separately for each thread. Each new thread needs to install its own unexpected function. Thus, each thread is in charge of its own unexpected handling.

In the current Microsoft implementation of C++ exception handling, unexpected calls terminate by default and is never called by the exception-handling run-time library. There is no particular advantage to calling unexpected rather than terminate.

Exception Handling Routines

See Also abort, set_terminate, terminate, unexpected


setvbuf

Controls stream buffering and buffer size.

int setvbuf( FILE *stream, char *buffer, int mode, size_t size );

Routine | Required Header | Compatibility
setvbuf | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

setvbuf returns 0 if successful, or a nonzero value if an illegal type or buffer size is specified.

Parameters

stream

Pointer to FILE structure

buffer

User-allocated buffer

mode

Mode of buffering

size

Buffer size in bytes. Allowable range: 2 < size < 32768. Internally, the value supplied for size is rounded down to the nearest multiple of 2.

Remarks

The setvbuf function allows the program to control both buffering and buffer size for stream. stream must refer to an open file that has not undergone an I/O operation since it was opened. The array pointed to by buffer is used as the buffer, unless it is NULL, in which case setvbuf uses an automatically allocated buffer of length size/2 * 2 bytes.

The mode must be _IOFBF, _IOLBF, or _IONBF. If mode is _IOFBF or _IOLBF, then size is used as the size of the buffer. If mode is _IONBF, the stream is unbuffered and size and buffer are ignored. Values for mode and their meanings are:

_IOFBF

Full buffering; that is, buffer is used as the buffer and size is used as the size of the buffer. If buffer is NULL, an automatically allocated buffer size bytes long is used.

_IOLBF

With MS-DOS, the same as _IOFBF.

_IONBF

No buffer is used, regardless of buffer or size.

Example

/* SETVBUF.C: This program opens two streams: stream1
 * and stream2. It then uses setvbuf to give stream1 a
 * user-defined buffer of 1024 bytes and stream2 no buffer.
 */

#include <stdio.h>

void main( void )
{
   char buf[1024];
   FILE *stream1, *stream2;

   if( ((stream1 = fopen( "data1", "a" )) != NULL) &&
       ((stream2 = fopen( "data2", "w" )) != NULL) )
   {
      if( setvbuf( stream1, buf, _IOFBF, sizeof( buf ) ) != 0 )
         printf( "Incorrect type or size of buffer for stream1\n" );
      else
         printf( "'stream1' now has a buffer of 1024 bytes\n" );
      if( setvbuf( stream2, NULL, _IONBF, 0 ) != 0 )
         printf( "Incorrect type or size of buffer for stream2\n" );
      else
         printf( "'stream2' now has no buffer\n" );
      _fcloseall();
   }
}

Output

'stream1' now has a buffer of 1024 bytes
'stream2' now has no buffer

Stream I/O Routines

See Also fclose, fflush, fopen, setbuf


signal

Sets interrupt signal handling.

void ( *signal( int sig, void (__cdecl *func) ( int sig [, int subcode ] )) ) ( int sig );

Routine | Required Header | Compatibility
signal | <signal.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

signal returns the previous value of func associated with the given signal. For example, if the previous value of func was SIG_IGN, the return value is also SIG_IGN. A return value of SIG_ERR indicates an error, in which case errno is set to EINVAL.

Parameters

sig

Signal value

func

Function to be executed

subcode

Optional subcode to the signal number

Remarks

The signal function allows a process to choose one of several ways to handle an interrupt signal from the operating system. The sig argument is the interrupt to which signal responds; it must be one of the following manifest constants, defined in SIGNAL.H.

sig Value | Description
SIGABRT | Abnormal termination
SIGFPE | Floating-point error
SIGILL | Illegal instruction
SIGINT | CTRL+C signal
SIGSEGV | Illegal storage access
SIGTERM | Termination request

By default, signal terminates the calling program with exit code 3, regardless of the value of sig.

Note SIGINT is not supported for any Win32 application including Windows NT and Windows 95. When a CTRL+C interrupt occurs, Win32 operating systems generate a new thread to specifically handle that interrupt. This can cause a single-thread application such as UNIX, to become multithreaded, resulting in unexpected behavior.

The func argument is an address to a signal handler that you write, or one of the manifest constants SIG_DFL or SIG_IGN, also defined in SIGNAL.H. If func is a function, it is installed as the signal handler for the given signal. The signal handler’s prototype requires one formal argument, sig, of type int. The operating system provides the actual argument through sig when an interrupt occurs; the argument is the signal that generated the interrupt. Thus you can use the six manifest constants (listed in the preceding table) inside your signal handler to determine which interrupt occurred and take appropriate action. For example, you can call signal twice to assign the same handler to two different signals, then test the sig argument inside the handler to take different actions based on the signal received.

If you are testing for floating-point exceptions (SIGFPE), func points to a function that takes an optional second argument that is one of several manifest constants defined in FLOAT.H of the form FPE_xxx. When a SIGFPE signal occurs, you can test the value of the second argument to determine the type of floating-point exception and then take appropriate action. This argument and its possible values are Microsoft extensions.

For floating-point exceptions, the value of func is not reset upon receiving the signal. To recover from floating-point exceptions, use setjmp with longjmp. If the function returns, the calling process resumes execution with the floating-point state of the process left undefined.

If the signal handler returns, the calling process resumes execution immediately following the point at which it received the interrupt signal. This is true regardless of the type of signal or operating mode.

Before the specified function is executed, the value of func is set to SIG_DFL. The next interrupt signal is treated as described for SIG_DFL, unless an intervening call to signal specifies otherwise. This feature lets you reset signals in the called function.

Because signal-handler routines are usually called asynchronously when an interrupt occurs, your signal-handler function may get control when a run-time operation is incomplete and in an unknown state. The list below summarizes restrictions that determine which functions you can use in your signal-handler routine.

  • Do not issue low-level or STDIO.H I/O routines (such as printf and fread).

  • Do not call heap routines or any routine that uses the heap routines (such as malloc, _strdup, and _putenv). See malloc for more information.

  • Do not use any function that generates a system call (e.g., _getcwd, time).

  • Do not use longjmp unless the interrupt is caused by a floating-point exception (i.e., sig is SIGFPE). In this case, first reinitialize the floating-point package with a call to _fpreset.

  • Do not use any overlay routines.

A program must contain floating-point code if it is to trap the SIGFPE exception with the function. If your program does not have floating-point code and requires the run-time library’s signal-handling code, simply declare a volatile double and initialize it to zero:

volatile double d = 0.0f;

The SIGILL, SIGSEGV, and SIGTERM signals are not generated under Windows NT. They are included for ANSI compatibility. Thus you can set signal handlers for these signals with signal, and you can also explicitly generate these signals by calling raise.

Signal settings are not preserved in spawned processes created by calls to _exec or _spawn functions. The signal settings are reset to the default in the new process.

Process and Environment Control Routines

See Also abort, _exec Functions, exit, _fpreset, _spawn Functions


sin, sinh

Calculate sines and hyperbolic sines.

double sin( double x );

double sinh( double x );

Routine | Required Header | Compatibility
sin | <math.h> | ANSI, Win 95, Win NT
sinh | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

sin returns the sine of x. If x is greater than or equal to 263, or less than or equal to –263, a loss of significance in the result occurs, in which case the function generates a _TLOSS error and returns an indefinite (same as a quiet NaN).

sinh returns the hyperbolic sine of x. If the result is too large, sinh sets errno to ERANGE and returns ±HUGE_VAL. You can modify error handling with _matherr.

Parameter

x

Angle in radians

Example

/* SINCOS.C: This program displays the sine, hyperbolic
 * sine, cosine, and hyperbolic cosine of pi / 2.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double pi = 3.1415926535;
   double x, y;

   x = pi / 2;
   y = sin( x );
   printf( "sin( %f ) = %f\n", x, y );
   y = sinh( x );
   printf( "sinh( %f ) = %f\n",x, y );
   y = cos( x );
   printf( "cos( %f ) = %f\n", x, y );
   y = cosh( x );
   printf( "cosh( %f ) = %f\n",x, y );
}

Output

sin( 1.570796 ) = 1.000000
sinh( 1.570796 ) = 2.301299
cos( 1.570796 ) = 0.000000
cosh( 1.570796 ) = 2.509178

Floating-Point Support Routines

See Also acos, asin, atan, cos, tan


_snprintf, _snwprintf

Write formatted data to a string.

int _snprintf( char *buffer, size_t count, const char *format [, argument] ... );

int _snwprintf( wchar_t *buffer, size_t count, const wchar_t *format [, argument] ... );

Routine | Required Header | Compatibility
_snprintf | <stdio.h> | Win 95, Win NT
_snwprintf | <stdio.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_snprintf returns the number of bytes stored in buffer, not counting the terminating null character. If the number of bytes required to store the data exceeds count, then count bytes of data are stored in buffer and a negative value is returned. _snwprintf returns the number of wide characters stored in buffer, not counting the terminating null wide character. If the storage required to store the data exceeds count wide characters, then count wide characters are stored in buffer and a negative value is returned.

Parameters

buffer

Storage location for output

count

Maximum number of characters to store

format

Format-control string

argument

Optional arguments

Remarks

The _snprintf function formats and stores count or fewer characters and values (including a terminating null character that is always appended unless count is zero or the formatted string length is greater than or equal to count characters) in buffer. Each argument (if any) is converted and output according to the corresponding format specification in format. The format consists of ordinary characters and has the same form and function as the format argument for printf. If copying occurs between strings that overlap, the behavior is undefined.

_snwprintf is a wide-character version of _snprintf; the pointer arguments to _snwprintf are wide-character strings. Detection of encoding errors in _snwprintf may differ from that in _snprintf. _snwprintf, like swprintf, writes output to a string rather than to a destination of type FILE.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_sntprintf | _snprintf | _snprintf | _snwprintf

Example

/* SPRINTF.C: This program uses sprintf to format various
 * data and place them in the string named buffer.
 */

#include <stdio.h>

void main( void )
{
   char  buffer[200], s[] = "computer", c = 'l';
   int   i = 35, j;
   float fp = 1.7320534f;

   /* Format and print various data: */
   j  = sprintf( buffer,     "\tString:    %s\n", s );
   j += sprintf( buffer + j, "\tCharacter: %c\n", c );
   j += sprintf( buffer + j, "\tInteger:   %d\n", i );
   j += sprintf( buffer + j, "\tReal:      %f\n", fp );

   printf( "Output:\n%s\ncharacter count = %d\n", buffer, j );
}

Output

Output:
   String:    computer
   Character: l
   Integer:   35
   Real:      1.732053

character count = 71

Stream I/O Routines

See Also sprintf, fprintf, printf, scanf, sscanf, vprintf Functions


_sopen, _wsopen

Open a file for sharing.

int _sopen( const char *filename, int oflag, int shflag [, int pmode ] );

int _wsopen( const wchar_t *filename, int oflag, int shflag [, int pmode ] );

Routine | Required Header | Optional Headers | Compatibility
_sopen | <io.h> | <fcntl.h>, <sys/types.h>, <sys/stat.h>, <share.h> | Win 95, Win NT
_wsopen | <io.h> or <wchar.h> | <fcntl.h>, <sys/types.h>, <sys/stat.h>, <share.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a file handle for the opened file. A return value of –1 indicates an error, in which case errno is set to one of the following values:

EACCES

Given path is a directory, or file is read-only, but an open-for-writing operation was attempted.

EEXIST

_O_CREAT and _O_EXCL flags were specified, but filename already exists.

EINVAL

Invalid oflag or shflag argument.

EMFILE

No more file handles available.

ENOENT

File or path not found.

Parameters

filename

Filename

oflag

Type of operations allowed

shflag

Type of sharing allowed

pmode

Permission setting

Remarks

The _sopen function opens the file specified by filename and prepares the file for shared reading or writing, as defined by oflag and shflag. _wsopen is a wide-character version of _sopen; the filename argument to _wsopen is a wide-character string. _wsopen and _sopen behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tsopen | _sopen | _sopen | _wsopen

The integer expression oflag is formed by combining one or more of the following manifest constants, defined in the file FCNTL.H. When two or more constants form the argument oflag, they are combined with the bitwise-OR operator ( | ).

_O_APPEND

Repositions file pointer to end of file before every write operation.

_O_BINARY

Opens file in binary (untranslated) mode. (See fopen for a description of binary mode.)

_O_CREAT

Creates and opens new file for writing. Has no effect if file specified by filename exists. The pmode argument is required when _O_CREAT is specified.

_O_CREAT | _O_SHORT_LIVED

Create file as temporary and if possible do not flush to disk. The pmode argument is required when _O_CREAT is specified.

_O_CREAT | _O_TEMPORARY

Create file as temporary; file is deleted when last file handle is closed. The pmode argument is required when _O_CREAT is specified.

_O_CREAT | _O_EXCL

Returns error value if file specified by filename exists. Applies only when used with _O_CREAT.

_O_NOINHERIT

Prevents creation of a shared file handle.

_O_RANDOM

Specifies primarily random access from disk.

_O_RDONLY

Opens file for reading only; cannot be specified with _O_RDWR or _O_WRONLY.

_O_RDWR

Opens file for both reading and writing; cannot be specified with _O_RDONLY or _O_WRONLY.

_O_SEQUENTIAL

Specifies primarily sequential access from disk

_O_TEXT

Opens file in text (translated) mode. (For more information, see Text and Binary Mode File I/O and fopen.)

_O_TRUNC

Opens file and truncates it to zero length; the file must have write permission. You cannot specify this flag with _O_RDONLY. _O_TRUNC used with _O_CREAT opens an existing file or creates a new file.

Warning The _O_TRUNC flag destroys the contents of the specified file.

_O_WRONLY

Opens file for writing only; cannot be specified with _O_RDONLY or _O_RDWR.

To specify the file access mode, you must specify either _O_RDONLY, _O_RDWR, or _O_WRONLY. There is no default value for the access mode.

The argument shflag is a constant expression consisting of one of the following manifest constants, defined in SHARE.H.

_SH_DENYRW

Denies read and write access to file

_SH_DENYWR

Denies write access to file

_SH_DENYRD

Denies read access to file

_SH_DENYNO

Permits read and write access

The pmode argument is required only when you specify _O_CREAT. If the file does not exist, pmode specifies the file’s permission settings, which are set when the new file is closed the first time. Otherwise pmode is ignored. pmode is an integer expression that contains one or both of the manifest constants _S_IWRITE and _S_IREAD, defined in SYS\STAT.H. When both constants are given, they are combined with the bitwise-OR operator. The meaning of pmode is as follows:

_S_IWRITE

Writing permitted

_S_IREAD

Reading permitted

_S_IREAD | _S_IWRITE

Reading and writing permitted

If write permission is not given, the file is read-only. Under Windows NT and Windows 95, all files are readable; it is not possible to give write-only permission. Thus the modes _S_IWRITE and _S_IREAD | _S_IWRITE are equivalent.

_sopen applies the current file-permission mask to pmode before setting the permissions (see _umask).

Example

/* LOCKING.C: This program opens a file with sharing. It locks
 * some bytes before reading them, then unlocks them. Note that the
 * program works correctly only if the file exists.
 */

#include <io.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/locking.h>
#include <share.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int  fh, numread;
   char buffer[40];

   /* Quit if can't open file or system doesn't
    * support sharing.
    */
   fh = _sopen( "locking.c", _O_RDWR, _SH_DENYNO,
                 _S_IREAD | _S_IWRITE );
   if( fh == -1 )
      exit( 1 );

   /* Lock some bytes and read them. Then unlock. */
   if( _locking( fh, LK_NBLCK, 30L ) != -1 )
   {
      printf( "No one can change these bytes while I'm reading them\n" );
      numread = _read( fh, buffer, 30 );
      printf( "%d bytes read: %.30s\n", numread, buffer );
      lseek( fh, 0L, SEEK_SET );
     _locking( fh, LK_UNLCK, 30L );
      printf( "Now I'm done. Do what you will with them\n" );
   }
   else
      perror( "Locking failed\n" );

   _close( fh );
}

Output

No one can change these bytes while I'm reading them
30 bytes read: /* LOCKING.C: This program ope
Now I'm done. Do what you will with them

Low-level I/O Routines

See Also _close, _creat, fopen, _fsopen, _open


_spawn, _wspawn Functions

Each of the _spawn functions creates and executes a new process.

_spawnl, _wspawnl | _spawnv, _wspawnv
_spawnle, _wspawnle | _spawnve, _wspawnve
_spawnlp, _wspawnlp | _spawnvp, _wspawnvp
_spawnlpe, _wspawnlpe | _spawnvpe, _wspawnvpe

The letter(s) at the end of the function name determine the variation.

_spawn Function Suffix | Description
e | envp, array of pointers to environment settings, is passed to new process.
l | Command-line arguments are passed individually to _spawn function. This suffix is typically used when number of parameters to new process is known in advance
p | PATH environment variable is used to find file to execute.
v | argv, array of pointers to command-line arguments, is passed to _spawn function. This suffix is typically used when number of parameters to new process is variable.

Remarks

The _spawn functions each create and execute a new process. They automatically handle multibyte-character string arguments as appropriate, recognizing multibyte-character sequences according to the multibyte code page currently in use. The _wspawn functions are wide-character versions of the _spawn functions; they do not handle multibyte-character strings. Otherwise, the _wspawn functions behave identically to their _spawn counterparts.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tspawnl | _spawnl | _spawnl | _wspawnl
_tspawnle | _spawnle | _spawnle | _wspawnle
_tspawnlp | _spawnlp | _spawnlp | _wspawnlp
_tspawnlpe | _spawnlpe | _spawnlpe | _wspawnlpe
_tspawnv | _spawnv | _spawnv | _wspawnv
_tspawnve | _spawnve | _spawnve | _wspawnve
_tspawnvp | _spawnvp | _spawnvp | _wspawnvp
_tspawnvpe | _spawnvpe | _spawnvpe | _wspawnvpe

Enough memory must be available for loading and executing the new process. The mode argument determines the action taken by the calling process before and during _spawn. The following values for mode are defined in PROCESS.H:

_P_OVERLAY

Overlays calling process with new process, destroying the calling process (same effect as _exec calls).

_P_WAIT

Suspends calling thread until execution of new process is complete (synchronous _spawn).

_P_NOWAIT or _P_NOWAITO

Continues to execute calling process concurrently with new process (asynchronous _spawn).

_P_DETACH

Continues to execute the calling process; new process is run in the background with no access to the console or keyboard. Calls to _cwait against the new process will fail (asynchronous _spawn).

The cmdname argument specifies the file that is executed as the new process and can specify a full path (from the root), a partial path (from the current working directory), or just a filename. If cmdname does not have a filename extension or does not end with a period (.), the _spawn function first tries the .COM extension, then the .EXE extension, the .BAT extension, and finally the .CMD extension.

If cmdname has an extension, only that extension is used. If cmdname ends with a period, the _spawn call searches for cmdname with no extension. The _spawnlp, _spawnlpe, _spawnvp, and _spawnvpe functions search for cmdname (using the same procedures) in the directories specified by the PATH environment variable.

If cmdname contains a drive specifier or any slashes (that is, if it is a relative path), the _spawn call searches only for the specified file; no path searching is done.

Note To ensure proper overlay initialization and termination, do not use the setjmp or longjmp function to enter or leave an overlay routine.

Arguments for the Spawned Process

To pass arguments to the new process, give one or more pointers to character strings as arguments in the _spawn call. These character strings form the argument list for the spawned process. The combined length of the strings forming the argument list for the new process must not exceed 1024 bytes. The terminating null character ('\0') for each string is not included in the count, but space characters (automatically inserted to separate arguments) are included.

You can pass argument pointers as separate arguments (in _spawnl, _spawnle, _spawnlp, and _spawnlpe) or as an array of pointers (in _spawnv, _spawnve, _spawnvp, and _spawnvpe). You must pass at least one argument, arg0 or argv[0], to the spawned process. By convention, this argument is the name of the program as you would type it on the command line. A different value does not produce an error.

The _spawnl, _spawnle, _spawnlp, and _spawnlpe calls are typically used in cases where the number of arguments is known in advance. The arg0 argument is usually a pointer to cmdname. The arguments arg1 through argn are pointers to the character strings forming the new argument list. Following argn, there must be a NULL pointer to mark the end of the argument list.

The _spawnv, _spawnve, _spawnvp, and _spawnvpe calls are useful when there is a variable number of arguments to the new process. Pointers to the arguments are passed as an array, argv. The argument argv[0] is usually a pointer to a path in real mode or to the program name in protected mode, and argv[1] through argv[n] are pointers to the character strings forming the new argument list. The argument argv[n +1] must be a NULL pointer to mark the end of the argument list.

Environment of the Spawned Process

Files that are open when a _spawn call is made remain open in the new process. In the _spawnl, _spawnlp, _spawnv, and _spawnvp calls, the new process inherits the environment of the calling process. You can use the _spawnle, _spawnlpe, _spawnve, and _spawnvpe calls to alter the environment for the new process by passing a list of environment settings through the envp argument. The argument envp is an array of character pointers, each element (except the final element) of which points to a null-terminated string defining an environment variable. Such a string usually has the form NAME=value where NAME is the name of an environment variable and value is the string value to which that variable is set. (Note that value is not enclosed in double quotation marks.) The final element of the envp array should be NULL. When envp itself is NULL, the spawned process inherits the environment settings of the parent process.

The _spawn functions can pass all information about open files, including the translation mode, to the new process. This information is passed in real mode through the C_FILE_INFO entry in the environment. The startup code normally processes this entry and then deletes it from the environment. However, if a _spawn function spawns a non-C process, this entry remains in the environment. Printing the environment shows graphics characters in the definition string for this entry because the environment information is passed in binary form in real mode. It should not have any other effect on normal operations. In protected mode, the environment information is passed in text form and therefore contains no graphics characters.

You must explicitly flush (using fflush or _flushall) or close any stream before calling a _spawn function.

You can control whether the open file information of a process is passed to its spawned processes. The external variable _fileinfo (declared in STDLIB.H) controls the passing of C_FILE_INFO information. If _fileinfo is 0 (the default), the C_FILE_INFO information is not passed to the new processes. If _fileinfo is not 0, C_FILE_INFO is passed to new processes. You can modify the default value of _fileinfo in one of two ways: link the supplied object file, FILEINFO.OBJ, into the program, or set the _fileinfo variable to a nonzero value directly in the C program.

New processes created by calls to _spawn routines do not preserve signal settings. Instead, the spawned process resets signal settings to the default.

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>

Process and Environment Control Routines

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system


_spawnl, _wspawnl

Create and execute a new process.

int _spawnl( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL );

int _wspawnl( int mode, const wchar_t *cmdname, const wchar_t *arg0, const wchar_t *arg1, ... const wchar_t *argn, NULL );

Routine | Required Header | Compatibility
_spawnl | <process.h> | Win 95, Win NT
_wspawnl | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnl or _wspawnl (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnl or _wspawnl (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

arg0, ... argn

List of pointers to arguments

Remarks

Each of these functions creates and executes a new process, passing each command-line argument as a separate parameter.

Process and Environment Control Routines | _spawn Functions Overview

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_spawnle, _wspawnle

Create and execute a new process.

int _spawnle( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL, const char *const *envp );

int _wspawnle( int mode, const wchar_t *cmdname, const wchar_t *arg0, const wchar_t *arg1, ... const wchar_t *argn, NULL, const wchar_t *const *envp );

Routine | Required Header | Compatibility
_spawnle | <process.h> | Win 95, Win NT
_wspawnle | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnle or _wspawnle (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnle or _wspawnle (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

arg0, ... argn

List of pointers to arguments

envp

Array of pointers to environment settings

Remarks

Each of these functions creates and executes a new process, passing each command-line argument as a separate parameter and also passing an array of pointers to environment settings.

Process and Environment Control Routines | _spawn Functions Overview

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_spawnlp, _wspawnlp

Create and execute a new process.

int _spawnlp( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL );

int _wspawnlp( int mode, const wchar_t *cmdname, const wchar_t *arg0, const wchar_t *arg1, ... const wchar_t *argn, NULL );

Routine | Required Header | Compatibility
_spawnlp | <process.h> | Win 95, Win NT
_wspawnlp | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnlp or _wspawnlp (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnlp or _wspawnlp (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

arg0, ... argn

List of pointers to arguments

Remarks

Each of these functions creates and executes a new process, passing each command-line argument as a separate parameter and using the PATH environment variable to find the file to execute.

Process and Environment Control Routines | _spawn Functions Overview

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_spawnlpe, _wspawnlpe

Create and execute a new process.

int _spawnlpe( int mode, const char *cmdname, const char *arg0, const char *arg1, ... const char *argn, NULL, const char *const *envp );

int _wspawnlpe( int mode, const wchar_t *cmdname, const wchar_t *arg0, const wchar_t *arg1, ... const wchar_t *argn, NULL, const wchar_t *const *envp );

Routine | Required Header | Compatibility
_spawnlpe | <process.h> | Win 95, Win NT
_wspawnlpe | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnlpe or _wspawnlpe (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnlpe or _wspawnlpe (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

arg0, ... argn

List of pointers to arguments

envp

Array of pointers to environment settings

Remarks

Each of these functions creates and executes a new process, passing each command-line argument as a separate parameter and also passing an array of pointers to environment settings. These functions use the PATH environment variable to find the file to execute.

Process and Environment Control Routines | _spawn Functions Overview

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_spawnv, _wspawnv

Create and execute a new process.

int _spawnv( int mode, const char *cmdname, const char *const *argv );

int _wspawnv( int mode, const wchar_t *cmdname, const wchar_t *const *argv );

Routine | Required Header | Compatibility
_spawnv | <stdio.h> or <process.h> | Win 95, Win NT
_wspawnv | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnv or _wspawnv (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnv or _wspawnv (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

argv

Array of pointers to arguments

Remarks

Each of these functions creates and executes a new process, passing an array of pointers to command-line arguments.

Process and Environment Control Routines | _spawn Functions Overview

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_spawnve, _wspawnve

Create and execute a new process.

int _spawnve( int mode, const char *cmdname, const char *const *argv, const char *const *envp );

int _wspawnve( int mode, const wchar_t *cmdname, const wchar_t *const *argv, const wchar_t *const *envp );

Routine | Required Header | Compatibility
_spawnve | <stdio.h> or <process.h> | Win 95, Win NT
_wspawnve | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnve or _wspawnve (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnve or _wspawnve (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

argv

Array of pointers to arguments

envp

Array of pointers to environment settings

Remarks

Each of these functions creates and executes a new process, passing an array of pointers to command-line arguments and an array of pointers to environment settings.

Process and Environment Control Routines | _spawn Functions Overview

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_spawnvp, _wspawnvp

Create and execute a new process.

int _spawnvp( int mode, const char *cmdname, const char *const *argv );

int _wspawnvp( int mode, const wchar_t *cmdname, const wchar_t *const *argv );

Routine | Required Header | Compatibility
_spawnvp | <stdio.h> or <process.h> | Win 95, Win NT
_wspawnvp | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnvp or _wspawnvp (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnvp or _wspawnvp (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

argv

Array of pointers to arguments

Remarks

Each of these functions creates and executes a new process, passing an array of pointers to command-line arguments and using the the PATH environment variable to find the file to execute.

Process and Environment Control Routines | _spawn Functions Overview

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_spawnvpe, _wspawnvpe

Create and execute a new process.

int _spawnvpe( int mode, const char *cmdname, const char *const *argv, const char *const *envp );

int _wspawnvpe( int mode, const wchar_t *cmdname, const wchar_t *const *argv, const wchar_t *const *envp );

Routine | Required Header | Compatibility
_spawnvpe | <stdio.h> or <process.h> | Win 95, Win NT
_wspawnvpe | <stdio.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value from a synchronous _spawnvpe or _wspawnvpe (_P_WAIT specified for mode) is the exit status of the new process. The return value from an asynchronous _spawnvpe or _wspawnvpe (_P_NOWAIT or _P_NOWAITO specified for mode) is the process handle. The exit status is 0 if the process terminated normally. You can set the exit status to a nonzero value if the spawned process specifically calls the exit routine with a nonzero argument. If the new process did not explicitly set a positive exit status, a positive exit status indicates an abnormal exit with an abort or an interrupt. A return value of –1 indicates an error (the new process is not started). In this case, errno is set to one of the following values:

E2BIG

Argument list exceeds 1024 bytes

EINVAL

mode argument is invalid

ENOENT

File or path is not found

ENOEXEC

Specified file is not executable or has invalid executable-file format

ENOMEM

Not enough memory is available to execute new process

Parameters

mode

Execution mode for calling process

cmdname

Path of file to be executed

argv

Array of pointers to arguments

envp

Array of pointers to environment settings

Remarks

Each of these functions creates and executes a new process, passing an array of pointers to command-line arguments and an array of pointers to environment settings. These functions use the PATH environment variable to find the file to execute.

See Also abort, atexit, _exec Functions, exit, _flushall, _getmbcp, _onexit, _setmbcp, system

Example

/* SPAWN.C: This program accepts a number in the range
 * 1-8 from the command line. Based on the number it receives,
 * it executes one of the eight different procedures that
 * spawn the process named child. For some of these procedures,
 * the CHILD.EXE file must be in the same directory; for
 * others, it only has to be in the same path.
 */

#include <stdio.h>
#include <process.h>

char *my_env[] =
{
   "THIS=environment will be",
   "PASSED=to child.exe by the",
   "_SPAWNLE=and",
   "_SPAWNLPE=and",
   "_SPAWNVE=and",
   "_SPAWNVPE=functions",
   NULL
};

void main( int argc, char *argv[] )
{
   char *args[4];

   /* Set up parameters to be sent: */
   args[0] = "child";
   args[1] = "spawn??";
   args[2] = "two";
   args[3] = NULL;

   if (argc <= 2)
   {
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }

   switch (argv[1][0])   /* Based on first letter of argument */
   {
   case '1':
      _spawnl( _P_WAIT, argv[2], argv[2], "_spawnl", "two", NULL );
      break;
   case '2':
      _spawnle( _P_WAIT, argv[2], argv[2], "_spawnle", "two",
               NULL, my_env );
      break;
   case '3':
      _spawnlp( _P_WAIT, argv[2], argv[2], "_spawnlp", "two", NULL );
      break;
   case '4':
      _spawnlpe( _P_WAIT, argv[2], argv[2], "_spawnlpe", "two",
                NULL, my_env );
      break;
   case '5':
      _spawnv( _P_OVERLAY, argv[2], args );
      break;
   case '6':
      _spawnve( _P_OVERLAY, argv[2], args, my_env );
      break;
   case '7':
      _spawnvp( _P_OVERLAY, argv[2], args );
      break;
   case '8':
      _spawnvpe( _P_OVERLAY, argv[2], args, my_env );
      break;
   default:
      printf( "SYNTAX: SPAWN <1-8> <childprogram>\n" );
      exit( 1 );
   }
   printf( "from SPAWN!\n" );
}

Output

SYNTAX: SPAWN <1-8> <childprogram>


_splitpath, _wsplitpath

Break a path name into components.

void _splitpath( const char *path, char *drive, char *dir, char *fname, char *ext );

void _wsplitpath( const wchar_t *path, wchar_t *drive, wchar_t *dir, wchar_t *fname, wchar_t *ext );

Routine | Required Header | Compatibility
_splitpath | <stdlib.h> | Win 95, Win NT
_wsplitpath | <stdlib.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

path

Full path

drive

Optional drive letter, followed by a colon (:)

dir

Optional directory path, including trailing slash. Forward slashes ( / ), backslashes ( \ ), or both may be used.

fname

Base filename (no extension)

ext

Optional filename extension, including leading period (.)

Remarks

The _splitpath function breaks a path into its four components. _splitpath automatically handles multibyte-character string arguments as appropriate, recognizing multibyte-character sequences according to the multibyte code page currently in use. _wsplitpath is a wide-character version of _splitpath; the arguments to _wsplitpath are wide-character strings. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tsplitpath | _splitpath | _splitpath | _wsplitpath

Each argument is stored in a buffer; the manifest constants _MAX_DRIVE, _MAX_DIR, _MAX_FNAME, and _MAX_EXT (defined in STDLIB.H) specify the maximum size necessary for each buffer. The other arguments point to buffers used to store the path elements. After a call to _splitpath is executed, these arguments contain empty strings for components not found in path. You can pass a NULL pointer to _splitpath for any component you don’t need.

Example

/* MAKEPATH.C */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char path_buffer[_MAX_PATH];
   char drive[_MAX_DRIVE];
   char dir[_MAX_DIR];
   char fname[_MAX_FNAME];
   char ext[_MAX_EXT];

   _makepath( path_buffer, "c", "\\sample\\crt\\", "makepath", "c" );
   printf( "Path created with _makepath: %s\n\n", path_buffer );
   _splitpath( path_buffer, drive, dir, fname, ext );
   printf( "Path extracted with _splitpath:\n" );
   printf( "  Drive: %s\n", drive );
   printf( "  Dir: %s\n", dir );
   printf( "  Filename: %s\n", fname );
   printf( "  Ext: %s\n", ext );
}

Output

Path created with _makepath: c:\sample\crt\makepath.c

Path extracted with _splitpath:
  Drive: c:
  Dir: \sample\crt\
  Filename: makepath
  Ext: .c

File Handling Routines

See Also _fullpath, _getmbcp, _makepath, _setmbcp


sprintf, swprintf

Write formatted data to a string.

int sprintf( char *buffer, const char *format [, argument] ... );

int swprintf( wchar_t *buffer, const wchar_t *format [, argument] ... );

Routine | Required Header | Compatibility
sprintf | <stdio.h> | ANSI, Win 95, Win NT
swprintf | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

sprintf returns the number of bytes stored in buffer, not counting the terminating null character. swprintf returns the number of wide characters stored in buffer, not counting the terminating null wide character.

Parameters

buffer

Storage location for output

format

Format-control string

argument

Optional arguments

For more information, see Format Specifications.

Remarks

The sprintf function formats and stores a series of characters and values in buffer. Each argument (if any) is converted and output according to the corresponding format specification in format. The format consists of ordinary characters and has the same form and function as the format argument for printf. A null character is appended after the last character written. If copying occurs between strings that overlap, the behavior is undefined.

swprintf is a wide-character version of sprintf; the pointer arguments to swprintf are wide-character strings. Detection of encoding errors in swprintf may differ from that in sprintf. swprintf and fwprintf behave identically except that swprintf writes output to a string rather than to a destination of type FILE.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_stprintf | sprintf | sprintf | swprintf

Example

/* SPRINTF.C: This program uses sprintf to format various
 * data and place them in the string named buffer.
 */

#include <stdio.h>

void main( void )
{
   char  buffer[200], s[] = "computer", c = 'l';
   int   i = 35, j;
   float fp = 1.7320534f;

   /* Format and print various data: */
   j  = sprintf( buffer,     "\tString:    %s\n", s );
   j += sprintf( buffer + j, "\tCharacter: %c\n", c );
   j += sprintf( buffer + j, "\tInteger:   %d\n", i );
   j += sprintf( buffer + j, "\tReal:      %f\n", fp );

   printf( "Output:\n%s\ncharacter count = %d\n", buffer, j );
}

Output

Output:
   String:    computer
   Character: l
   Integer:   35
   Real:      1.732053

character count = 71

Stream I/O Routines

See Also _snprintf, fprintf, printf, scanf, sscanf, vprintf Functions


sqrt

Calculates the square root.

double sqrt( double x );

Routine | Required Header | Compatibility
sqrt | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The sqrt function returns the square-root of x. If x is negative, sqrt returns an indefinite (same as a quiet NaN). You can modify error handling with _matherr.

Parameter

x

Nonnegative floating-point value

Example

/* SQRT.C: This program calculates a square root. */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   double question = 45.35, answer;

   answer = sqrt( question );
   if( question < 0 )
      printf( "Error: sqrt returns %.2f\n, answer" );
   else
      printf( "The square root of %.2f is %.2f\n", question, answer );
}

Output

The square root of 45.35 is 6.73

Floating-Point Support Routines

See Also exp, log, pow


srand

Sets a random starting point.

void srand( unsigned int seed );

Routine | Required Header | Compatibility
srand | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameter

seed

Seed for random-number generation

Remarks

The srand function sets the starting point for generating a series of pseudorandom integers. To reinitialize the generator, use 1 as the seed argument. Any other value for seed sets the generator to a random starting point. rand retrieves the pseudorandom numbers that are generated. Calling rand before any call to srand generates the same sequence as calling srand with seed passed as 1.

Example

/* RAND.C: This program seeds the random-number generator
 * with the time, then displays 10 random integers.
 */

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

void main( void )
{
   int i;

   /* Seed the random-number generator with current time so that
    * the numbers will be different every time we run.
    */
   srand( (unsigned)time( NULL ) );

   /* Display 10 numbers. */
   for( i = 0;   i < 10;i++ )
      printf( "  %6d\n", rand() );
}

Output

    6929
    8026
   21987
   30734
   20587
    6699
   22034
   25051
    7988
   10104

Floating-Point Support Routine

See Also rand


sscanf, swscanf

Read formatted data from a string.

int sscanf( const char *buffer, const char *format [, argument ] ... );

int swscanf( const wchar_t *buffer, const wchar_t *format [, argument ] ... );

Routine | Required Header | Compatibility
sscanf | <stdio.h> | ANSI, Win 95, Win NT
swscanf | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the number of fields successfully converted and assigned; the return value does not include fields that were read but not assigned. A return value of 0 indicates that no fields were assigned. The return value is EOF for an error or if the end of the string is reached before the first conversion.

Parameters

buffer

Stored data

format

Format-control string

argument

Optional arguments

For more information, see Format Specifications.

Remarks

The sscanf function reads data from buffer into the location given by each argument. Every argument must be a pointer to a variable with a type that corresponds to a type specifier in format. The format argument controls the interpretation of the input fields and has the same form and function as the format argument for the scanf function; see scanf for a complete description of format. If copying takes place between strings that overlap, the behavior is undefined.

swscanf is a wide-character version of sscanf; the arguments to swscanf are wide-character strings. sscanf does not handle multibyte hexadecimal characters. swscanf does not handle Unicode fullwidth hexadecimal or “compatibility zone” characters. Otherwise, swscanf and sscanf behave identically.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_stscanf | sscanf | sscanf | swscanf

Example

/* SSCANF.C: This program uses sscanf to read data items
 * from a string named tokenstring, then displays them.
 */

#include <stdio.h>

void main( void )
{
   char  tokenstring[] = "15 12 14...";
   char  s[81];
   char  c;
   int   i;
   float fp;

   /* Input various data from tokenstring: */
   sscanf( tokenstring, "%s", s );
   sscanf( tokenstring, "%c", &c );
   sscanf( tokenstring, "%d", &i );
   sscanf( tokenstring, "%f", &fp );

   /* Output the data read */
   printf( "String    = %s\n", s );
   printf( "Character = %c\n", c );
   printf( "Integer:  = %d\n", i );
   printf( "Real:     = %f\n", fp );
}

Output

String    = 15
Character = 1
Integer:  = 15
Real:     = 15.000000

Stream I/O Routines

See Also fscanf, scanf, sprintf, _snprintf


_stat, _wstat, _stati64, _wstati64

Get status information on a file.

int _stat( const char *path, struct _stat *buffer );

__int64 _stati64( const char *path, struct _stat *buffer );

int _wstat( const wchar_t *path, struct _stat *buffer );

__int64 _wstati64( const wchar_t *path, struct _stat *buffer );

Routine | Required Header | Optional Headers | Compatibility
_stat | <sys/types.h> followed by <sys/stat.h> | <errno.h> | Win 95, Win NT
_wstat | <sys/types.h> followed by <sys/stat.h> or <wchar.h> | <errno.h> | Win NT
_stati64 | <sys/types.h> followed by <sys/stat.h> | <errno.h> | Win 95, Win NT
_wstati64 | <sys/types.h> followed by <sys/stat.h> or <wchar.h> | <errno.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if the file-status information is obtained. A return value of –1 indicates an error, in which case errno is set to ENOENT, indicating that the filename or path could not be found.

Parameters

path

Path of existing file

buffer

Pointer to structure that stores results

Remarks

The _stat function obtains information about the file or directory specified by path and stores it in the structure pointed to by buffer. _stat automatically handles multibyte-character string arguments as appropriate, recognizing multibyte-character sequences according to the multibyte code page currently in use.

_wstat is a wide-character version of _stat; the path argument to _wstat is a wide-character string. _wstat and _stat behave identically except that _wstat does not handle multibyte-character strings.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tstat | _stat | _stat | _wstat
_tstati64 | _stati64 | _stati64 | _wstati64

The _stat structure, defined in SYS\STAT.H, includes the following fields.

st_gid

Numeric identifier of group that owns file (UNIX-specific) This field will always be zero on NT systems. A redirected file is classified as an NT file.

st_atime

Time of last access of file.

st_ctime

Time of creation of file.

st_dev

Drive number of the disk containing the file (same as st_rdev).

st_ino

Number of the information node (the inode) for the file (UNIX-specific). On UNIX file systems, the inode describes the file date and time stamps, permissions, and content. When files are hard-linked to one another, they share the same inode. The inode, and therefore st_ino, has no meaning in the FAT, HPFS, or NTFS file systems.

st_mode

Bit mask for file-mode information. The _S_IFDIR bit is set if path specifies a directory; the _S_IFREG bit is set if path specifies an ordinary file or a device. User read/write bits are set according to the file’s permission mode; user execute bits are set according to the filename extension.

st_mtime

Time of last modification of file.

st_nlink

Always 1 on non-NTFS file systems.

st_rdev

Drive number of the disk containing the file (same as st_dev).

st_size

Size of the file in bytes; a 64-bit integer for _stati64 and _wstati64

st_uid

Numeric identifier of user who owns file (UNIX-specific). This field will always be zero on NT systems. A redirected file is classified as an NT file.

If path refers to a device, the size, time, _dev, and _rdev fields in the _stat structure are meaningless. Because STAT.H uses the _dev_t type that is defined in TYPES.H, you must include TYPES.H before STAT.H in your code.

Example

/* STAT.C: This program uses the _stat function to
 * report information about the file named STAT.C.
 */

#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

void main( void )
{
   struct _stat buf;
   int result;
   char buffer[] = "A line to output";

   /* Get data associated with "stat.c": */
   result = _stat( "stat.c", &buf );

   /* Check if statistics are valid: */
   if( result != 0 )
      perror( "Problem getting information" );
   else
   {
      /* Output some of the statistics: */
      printf( "File size     : %ld\n", buf.st_size );
      printf( "Drive         : %c:\n", buf.st_dev + 'A' );
      printf( "Time modified : %s", ctime( &buf.st_atime ) );
   }
}

Output

File size     : 745
Drive         : C:
Time modified : Tue May 03 00:00:00 1994

File Handling Routines

See Also _access, _fstat, _getmbcp, _setmbcp


_status87, _statusfp

Get the floating point status word.

unsigned int _status87( void );

unsigned int _statusfp( void );

Routine | Required Header | Compatibility
_status87 | <float.h> | Win 95, Win NT
_statusfp | <float.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The bits in the value returned indicate the floating-point status. See the FLOAT.H include file for a complete definition of the bits returned by _status87.

Many math library functions modify the 8087/80287 status word, with unpredictable results. Return values from _clear87 and _status87 are more reliable if fewer floating-point operations are performed between known states of the floating-point status word.

Remarks

The _status87 function gets the floating-point status word. The status word is a combination of the 8087/80287/80387 status word and other conditions detected by the 8087/80287/80387 exception handler, such as floating-point stack overflow and underflow. Unmasked exceptions are checked for before returning the contents of the status word. This means that the caller is informed of pending exceptions.

_statusfp is a platform-independent, portable version of _status87. It is identical to _status87 on Intel (x86) platforms and is also supported by the MIPS platform. To ensure that your floating-point code is portable to MIPS, use _statusfp. If you are only targeting x86 platforms, use either _status87 or _statusfp.

Example

/* STATUS87.C: This program creates various floating-point errors and
 * then uses _status87 to display messages indicating these problems.
 * Compile this program with optimizations disabled (/Od). Otherwise,
 * the optimizer removes the code related to the unused floating-
 * point values.
 */

#include <stdio.h>
#include <float.h>

void main( void )
{
   double a = 1e-40, b;
   float  x, y;

   printf( "Status = %.4x - clear\n",_status87() );

   /* Assignment into y is inexact & underflows: */
   y = a;
   printf( "Status = %.4x - inexact, underflow\n", _status87() );

   /* y is denormal: */
   b = y;
   printf( "Status = %.4x - inexact underflow, denormal\n",
           _status87() );

   /* Clear user 8087: */
   _clear87();
}

Output

Status = 0000 - clear
Status = 0003 - inexact, underflow
Status = 80003 - inexact underflow, denormal

Floating-Point Support Routines

See Also _clear87, _control87


strcat, wcscat, _mbscat

Append a string.

char *strcat( char *strDestination, const char *strSource );

wchar_t *wcscat( wchar_t *strDestination, const wchar_t *strSource );

unsigned char *_mbscat( unsigned char *strDestination, const unsigned char *strSource );

Routine | Required Header | Compatibility
strcat | <string.h> | ANSI, Win 95, Win NT
wcscat | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbscat | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the destination string (strDestination). No return value is reserved to indicate an error.

Parameters

strDestination

Null-terminated destination string

strSource

Null-terminated source string

Remarks

The strcat function appends strSource to strDestination and terminates the resulting string with a null character. The initial character of strSource overwrites the terminating null character of strDestination. No overflow checking is performed when strings are copied or appended. The behavior of strcat is undefined if the source and destination strings overlap.

wcscat and _mbscat are wide-character and multibyte-character versions of strcat. The arguments and return value of wcscat are wide-character strings; those of _mbscat are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcscat | strcat | _mbscat | wcscat

Example

/* STRCPY.C: This program uses strcpy
 * and strcat to build a phrase.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[80];
   strcpy( string, "Hello world from " );
   strcat( string, "strcpy " );
   strcat( string, "and " );
   strcat( string, "strcat!" );
   printf( "String = %s\n", string );
}

Output

String = Hello world from strcpy and strcat!

String Manipulation Routines

See Also strncat, strncmp, strncpy, _strnicmp, strrchr, strspn


strchr, wcschr, _mbschr

Find a character in a string.

char *strchr( const char *string, int c );

wchar_t *wcschr( const wchar_t *string, wint_t c );

unsigned char *_mbschr( const unsigned char *string, unsigned int c );

Routine | Required Header | Compatibility
strchr | <string.h> | ANSI, Win 95, Win NT
wcschr | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbschr | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the first occurrence of c in string, or NULL if c is not found.

Parameters

string

Null-terminated source string

c

Character to be located

Remarks

The strchr function finds the first occurrence of c in string, or it returns NULL if c is not found. The null-terminating character is included in the search.

wcschr and _mbschr are wide-character and multibyte-character versions of strchr. The arguments and return value of wcschr are wide-character strings; those of _mbschr are multibyte-character strings. _mbschr recognizes multibyte-character sequences according to the multibyte code page currently in use. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcschr | strchr | _mbschr | wcschr

Example

/* STRCHR.C: This program illustrates searching for a character
 * with strchr (search forward) or strrchr (search backward).
 */

#include <string.h>
#include <stdio.h>

int  ch = 'r';

char string[] = "The quick brown dog jumps over the lazy fox";
char fmt1[] =   "         1         2         3         4         5";
char fmt2[] =   "12345678901234567890123456789012345678901234567890";

void main( void )
{
   char *pdest;
   int result;

   printf( "String to be searched: \n\t\t%s\n", string );
   printf( "\t\t%s\n\t\t%s\n\n", fmt1, fmt2 );
   printf( "Search char:\t%c\n", ch );

   /* Search forward. */
   pdest = strchr( string, ch );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\tfirst %c found at position %d\n\n",
              ch, result );
   else
      printf( "Result:\t%c not found\n" );

   /* Search backward. */
   pdest = strrchr( string, ch );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\tlast %c found at position %d\n\n", ch, result );
   else
      printf( "Result:\t%c not found\n" );
}

Output

String to be searched:
      The quick brown dog jumps over the lazy fox
               1         2         3         4         5
      12345678901234567890123456789012345678901234567890

Search char:   r
Result:   first r found at position 12

Result:   last r found at position 30

String Manipulation Routines

See Also strcspn, strncat, strncmp, strncpy, _strnicmp, strpbrk, strrchr, strstr


strcmp, wcscmp, _mbscmp

Compare strings.

int strcmp( const char *string1, const char *string2 );

int wcscmp( const wchar_t *string1, const wchar_t *string2 );

int _mbscmp(const unsigned char *string1, const unsigned char *string2 );

Routine | Required Header | Compatibility
strcmp | <string.h> | ANSI, Win 95, Win NT
wcscmp | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbscmp | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value for each of these functions indicates the lexicographic relation of string1 to string2.

Value | Relationship of string1 to string2
< 0 | string1 less than string2
0 | string1 identical to string2
> 0 | string1 greater than string2

On an error, _mbscmp returns _NLSCMPERROR, which is defined in STRING.H and MBSTRING.H.

Parameters

string1, string2

Null-terminated strings to compare

Remarks

The strcmp function compares string1 and string2 lexicographically and returns a value indicating their relationship. wcscmp and _mbscmp are wide-character and multibyte-character versions of strcmp. The arguments and return value of wcscmp are wide-character strings; those of _mbscmp are multibyte-character strings. _mbscmp recognizes multibyte-character sequences according to the current multibyte code page and returns _NLSCMPERROR on an error. (For more information, see Code Pages.) These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcscmp | strcmp | _mbscmp | wcscmp

The strcmp functions differ from the strcoll functions in that strcmp comparisons are not affected by locale, whereas the manner of strcoll comparisons is determined by the LC_COLLATE category of the current locale. For more information on the LC_COLLATE category, see setlocale.

In the “C” locale, the order of characters in the character set (ASCII character set) is the same as the lexicographic character order. However, in other locales, the order of characters in the character set may differ from the lexicographic order. For example, in certain European locales, the character 'a' (value 0x61) precedes the character 'ä' (value 0xE4) in the character set, but the character 'ä' precedes the character 'a' lexicographically.

In locales for which the character set and the lexicographic character order differ, use strcoll rather than strcmp for lexicographic comparison of strings according to the LC_COLLATE category setting of the current locale. Thus, to perform a lexicographic comparison of the locale in the above example, use strcoll rather than strcmp. Alternatively, you can use strxfrm on the original strings, then use strcmp on the resulting strings.

_stricmp, _wcsicmp, and _mbsicmp compare strings by first converting them to their lowercase forms.Two strings containing characters located between 'Z' and 'a' in the ASCII table ('[', '\', ']', '^', '_', and '`') compare differently, depending on their case. For example, the two strings "ABCDE" and "ABCD^" compare one way if the comparison is lowercase ("abcde" > "abcd^") and the other way ("ABCDE" < "ABCD^") if the comparison is uppercase.

Example

/* STRCMP.C */

#include <string.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown dog jumps over the lazy fox";

void main( void )
{
   char tmp[20];
   int result;
   /* Case sensitive */
   printf( "Compare strings:\n\t%s\n\t%s\n\n", string1, string2 );
   result = strcmp( string1, string2 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "\tstrcmp:   String 1 is %s string 2\n", tmp );
   /* Case insensitive (could use equivalent _stricmp) */
   result = _stricmp( string1, string2 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "\t_stricmp:  String 1 is %s string 2\n", tmp );
}

Output

Compare strings:
   The quick brown dog jumps over the lazy fox
   The QUICK brown dog jumps over the lazy fox

   strcmp:   String 1 is greater than string 2
   _stricmp:  String 1 is equal to string 2

String Manipulation Routines

See Also memcmp, _memicmp, strcoll Functions, _stricmp, strncmp, _strnicmp, strrchr, strspn, strxfrm


strcoll Functions

Each of the strcoll and wcscoll functions compares two strings according to the LC_COLLATE category setting of the locale code page currently in use. Each of the _mbscoll functions compares two strings according to the multibyte code page currently in use. Use the coll functions for string comparisons when there is a difference between the character set order and the lexicographic character order in the current code page and this difference is of interest for the comparison. Use the corresponding cmp functions to test only for string equality.

strcoll Functions

SBCS | Unicode | MBCS | Description
strcoll | wcscoll | _mbscoll | Collate two strings
_stricoll | _wcsicoll | _mbsicoll | Collate two strings (case insensitive)
_strncoll | _wcsncoll | _mbsncoll | Collate first count characters of two strings
_strnicoll | _wcsnicoll | _mbsnicoll | Collate first count characters of two strings (case-insensitive)

Remarks

The single-byte character (SBCS) versions of these functions (strcoll, stricoll, _strncoll, and _strnicoll) compare string1 and string2 according to the LC_COLLATE category setting of the current locale. These functions differ from the corresponding strcmp functions in that the strcoll functions use locale code page information that provides collating sequences. For string comparisons in locales in which the character set order and the lexicographic character order differ, the strcoll functions should be used rather than the corresponding strcmp functions. For more information on LC_COLLATE, see setlocale.

For some code pages and corresponding character sets, the order of characters in the character set may differ from the lexicographic character order. In the “C” locale, this is not the case: the order of characters in the ASCII character set is the same as the lexicographic order of the characters. However, in certain European code pages, for example, the character 'a' (value 0x61) precedes the character 'ä' (value 0xE4) in the character set, but the character 'ä' precedes the character 'a' lexicographically. To perform a lexicographic comparison in such an instance, use strcoll rather than strcmp. Alternatively, you can use strxfrm on the original strings, then use strcmp on the resulting strings.

strcoll, stricoll, _strncoll, and _strnicoll automatically handle multibyte-character strings according to the locale code page currently in use, as do their wide-character (Unicode) counterparts. The multibyte-character (MBCS) versions of these functions, however, collate strings on a character basis according to the multibyte code page currently in use.

Because the coll functions collate strings lexicographically for comparison, whereas the cmp functions simply test for string equality, the coll functions are much slower than the corresponding cmp versions. Therefore, the coll functions should be used only when there is a difference between the character set order and the lexicographic character order in the current code page and this difference is of interest for the string comparison.

Locale Routines | String Manipulation Routines

See Also localeconv, _mbsnbcoll, setlocale, strcmp, strncmp, _strnicmp, strxfrm


strcoll, wcscoll, _mbscoll

Compare strings using locale-specific information.

int strcoll( const char *string1, const char *string2 );

int wcscoll( const wchar_t *string1, const wchar_t *string2 );

int _mbscoll( const unsigned char *string1, const unsigned char *string2 );

Routine | Required Header | Compatibility
strcoll | <string.h> | ANSI, Win 95, Win NT
wcscoll | <wchar.h>, <string.h> | ANSI, Win 95, Win NT
_mbscoll | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a value indicating the relationship of string1 to string2, as follows.

Return Value | Relationship of string1 to string2
< 0 | string1 less than string2
0 | string1 identical to string2
> 0 | string1 greater than string2

Each of these functions returns _NLSCMPERROR on an error. To use _NLSCMPERROR, include either STRING.H or MBSTRING.H. wcscoll can fail if either string1 or string2 contains wide-character codes outside the domain of the collating sequence. When an error occurs, wcscoll may set errno to EINVAL. To check for an error on a call to wcscoll, set errno to 0 and then check errno after calling wcscoll.

Parameters

string1, string2

Null-terminated strings to compare

Remarks

Each of these functions performs a case-sensitive comparison of string1 and string2 according to the code page currently in use. These functions should be used only when there is a difference between the character set order and the lexicographic character order in the current code page and this difference is of interest for the string comparison.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcscoll | strcoll | _mbscoll | wcscoll

Locale Routines, String Manipulation Routines | strcoll Functions Overview

See Also localeconv, _mbsnbcoll, setlocale, strcmp, _stricmp, strncmp, _strnicmp, strxfrm


_stricoll, _wcsicoll, _mbsicoll

Compare strings using locale-specific information.

int _stricoll( const char *string1, const char *string2 );

int _wcsicoll( const wchar_t *string1, const wchar_t *string2 );

int _mbsicoll( const unsigned char *string1, const unsigned char *string2 );

Routine | Required Header | Compatibility
_stricoll | <string.h> | Win 95, Win NT
_wcsicoll | <wchar.h>, <string.h> | Win 95, Win NT
_mbsicoll | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a value indicating the relationship of string1 to string2, as follows.

Return Value | Relationship of string1 to string2
< 0 | string1 less than string2
0 | string1 identical to string2
> 0 | string1 greater than string2

Each of these functions returns _NLSCMPERROR. To use _NLSCMPERROR, include either STRING.H or MBSTRING.H. _wcsicoll can fail if either string1 or string2 contains wide-character codes outside the domain of the collating sequence. When an error occurs, _wcsicoll may set errno to EINVAL. To check for an error on a call to _wcsicoll, set errno to 0 and then check errno after calling _wcsicoll.

Parameters

string1, string2

Null-terminated strings to compare

Remarks

Each of these functions performs a case-insensitive comparison of string1 and string2 according to the code page currently in use. These functions should be used only when there is a difference between the character set order and the lexicographic character order in the current code page and this difference is of interest for the string comparison.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsicoll | _stricoll | _mbsicoll | _wcsicoll

Locale Routines, String Manipulation Routines | strcoll Functions Overview

See Also localeconv, _mbsnbcoll, setlocale, strcmp, _stricmp, strncmp, _strnicmp, strxfrm


_strncoll, _wcsncoll, _mbsncoll

Compare strings using locale-specific information.

int _strncoll( const char *string1, const char *string2, size_t count );

int _wcsncoll( const wchar_t *string1, const wchar_t *string2, size_t count );

int _mbsncoll( const unsigned char *string1, const unsigned char *string2, size_t count );

Routine | Required Header | Compatibility
_strncoll | <string.h> | Win 95, Win NT
_wcsncoll | <wchar.h> or <string.h> | Win 95, Win NT
_mbsncoll | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a value indicating the relationship of the substrings of string1 and string2, as follows.

Return Value | Relationship of string1 to string2
< 0 | string1 less than string2
0 | string1 identical to string2
> 0 | string1 greater than string2

Each of these functions returns _NLSCMPERROR. To use _NLSCMPERROR, include either STRING.H or MBSTRING.H. _wcsncoll can fail if either string1 or string2 contains wide-character codes outside the domain of the collating sequence. When an error occurs, _wcsncoll may set errno to EINVAL. To check for an error on a call to _wcsncoll, set errno to 0 and then check errno after calling _wcsncoll.

Parameters

string1, string2

Null-terminated strings to compare

count

Number of characters to compare

Remarks

Each of these functions performs a case-sensitive comparison of the first count characters in string1 and string2 according to the code page currently in use. These functions should be used only when there is a difference between the character set order and the lexicographic character order in the current code page and this difference is of interest for the string comparison.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsnccoll | _strncoll | _mbsnbcoll | _wcsncoll
_tcsncoll | _strncoll | _mbsnbcoll | _wcsncoll

Locale Routines, String Manipulation Routines | strcoll Functions Overview

See Also localeconv, _mbsnbcoll, setlocale, strcmp, _stricmp, strncmp, _strnicmp, strxfrm


_strnicoll, _wcsnicoll, _mbsnicoll

Compare strings using locale-specific information.

int _strnicoll( const char *string1, const char *string2, size_t count );

int _wcsnicoll( const wchar_t *string1, const wchar_t *string2 , size_t count );

int _mbsnicoll( const unsigned char *string1, const unsigned char *string2, size_t count );

Routine | Required Header | Compatibility
_strnicoll | <string.h> | Win 95, Win NT
_wcsnicoll | <wchar.h> or <string.h> | Win 95, Win NT
_mbsnicoll | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a value indicating the relationship of the substrings of string1 and string2, as follows.

Return Value | Relationship of string1 to string2
< 0 | string1 less than string2
0 | string1 identical to string2
> 0 | string1 greater than string2

Each of these functions returns _NLSCMPERROR. To use _NLSCMPERROR, include either STRING.H or MBSTRING.H. _wcsnicoll can fail if either string1 or string2 contains wide-character codes outside the domain of the collating sequence. When an error occurs, _wcsnicoll may set errno to EINVAL. To check for an error on a call to _wcsnicoll, set errno to 0 and then check errno after calling _wcsnicoll.

Parameters

string1, string2

Null-terminated strings to compare

count

Number of characters to compare

Remarks

Each of these functions performs a case-insensitive comparison of the first count characters in string1 and string2 according to the code page currently in use. These functions should be used only when there is a difference between the character set order and the lexicographic character order in the current code page and this difference is of interest for the string comparison.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncicoll | _strnicoll | _mbsnbicoll | _wcsnicoll
_tcsnicoll | _strnicoll | _mbsnbicoll | _wcsnicoll

Locale Routines | String Manipulation Routines | strcoll Functions Overview

See Also localeconv, _mbsnbcoll, setlocale, strcmp, _stricmp, strncmp, _strnicmp, strxfrm


strcpy, wcscpy, _mbscpy

Copy a string.

char *strcpy( char *strDestination, const char *strSource );

wchar_t *wcscpy( wchar_t *strDestination, const wchar_t *strSource );

unsigned char *_mbscpy( unsigned char *strDestination, const unsigned char *strSource );

Routine | Required Header | Compatibility
strcpy | <string.h> | ANSI, Win 95, Win NT
wcscpy | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbscpy | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the destination string. No return value is reserved to indicate an error.

Parameters

strDestination

Destination string

strSource

Null-terminated source string

Remarks

The strcpy function copies strSource, including the terminating null character, to the location specified by strDestination. No overflow checking is performed when strings are copied or appended. The behavior of strcpy is undefined if the source and destination strings overlap.

wcscpy and _mbscpy are wide-character and multibyte-character versions of strcpy. The arguments and return value of wcscpy are wide-character strings; those of _mbscpy are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcscpy | strcpy | _mbscpy | wcscpy

Example

/* STRCPY.C: This program uses strcpy
 * and strcat to build a phrase.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[80];
   strcpy( string, "Hello world from " );
   strcat( string, "strcpy " );
   strcat( string, "and " );
   strcat( string, "strcat!" );
   printf( "String = %s\n", string );
}

Output

String = Hello world from strcpy and strcat!

String Manipulation Routines

See Also strcat, strcmp, strncat, strncmp, strncpy, _strnicmp, strrchr, strspn


strcspn, wcscspn, _mbscspn

Find a substring in a string.

size_t strcspn( const char *string, const char *strCharSet );

size_t wcscspn( const wchar_t *string, const wchar_t *strCharSet );

size_t _mbscspn( const unsigned char *string, const unsigned char *strCharSet );

Routine | Required Header | Compatibility
strcspn | <string.h> | ANSI, Win 95, Win NT
wcscspn | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbscspn | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns an integer value specifying the length of the initial segment of string that consists entirely of characters not in strCharSet. If string begins with a character that is in strCharSet, the function returns 0. No return value is reserved to indicate an error.

Parameters

string

Null-terminated searched string

strCharSet

Null-terminated character set

Remarks

The strcspn function returns the index of the first occurrence of a character in string that belongs to the set of characters in strCharSet. Terminating null characters are included in the search.

wcscspn and _mbscspn are wide-character and multibyte-character versions of strcspn. The arguments of wcscspn are wide-character strings; those of _mbscspn are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcscspn | strcspn | _mbscspn | wcscspn

Example

/* STRCSPN.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[] = "xyzabc";
   int  pos;

   pos = strcspn( string, "abc" );
   printf( "First a, b or c in %s is at character %d\n",
           string, pos );
}

Output

First a, b or c in xyzabc is at character 3

String Manipulation Routines

See Also strncat, strncmp, strncpy, _strnicmp, strrchr, strspn


_strdate, _wstrdate

Copy a date to a buffer.

char *_strdate( char *datestr );

wchar_t *_wstrdate( wchar_t *datestr );

Routine | Required Header | Compatibility
_strdate | <time.h> | Win 95, Win NT
_wstrdate | <time.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the resulting character string datestr.

Parameter

datestr

A pointer to a buffer containing the formatted date string

Remarks

The _strdate function copies a date to the buffer pointed to by datestr, formatted mm/dd/yy, where mm is two digits representing the month, dd is two digits representing the day, and yy is the last two digits of the year. For example, the string 12/05/99 represents December 5, 1999. The buffer must be at least 9 bytes long.

_wstrdate is a wide-character version of _strdate; the argument and return value of _wstrdate are wide-character strings. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tstrdate | _strdate | _strdate | _wstrdate

Example

/* TIMES.C illustrates various time and date functions including:
 *      time            _ftime          ctime       asctime
 *      localtime       gmtime          mktime      _tzset
 *      _strtime        _strdate        strftime
 *
 * Also the global variable:
 *      _tzname
 */

#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <string.h>

void main()
{
    char tmpbuf[128], ampm[] = "AM";
    time_t ltime;
    struct _timeb tstruct;
    struct tm *today, *gmt, xmas = { 0, 0, 12, 25, 11, 93 };

    /* Set time zone from TZ environment variable. If TZ is not set,
     * the operating system is queried to obtain the default value
     * for the variable.
     */
    _tzset();

    /* Display operating system-style date and time. */
    _strtime( tmpbuf );
    printf( "OS time:\t\t\t\t%s\n", tmpbuf );
    _strdate( tmpbuf );
    printf( "OS date:\t\t\t\t%s\n", tmpbuf );

    /* Get UNIX-style time and display as number and string. */
    time( &ltime );
    printf( "Time in seconds since UTC 1/1/70:\t%ld\n", ltime );
    printf( "UNIX time and date:\t\t\t%s", ctime( &ltime ) );

    /* Display UTC. */
    gmt = gmtime( &ltime );
    printf( "Coordinated universal time:\t\t%s", asctime( gmt ) );

    /* Convert to time structure and adjust for PM if necessary. */
    today = localtime( &ltime );
    if( today->tm_hour > 12 )
    {
   strcpy( ampm, "PM" );
   today->tm_hour -= 12;
    }
    if( today->tm_hour == 0 )  /* Adjust if midnight hour. */
   today->tm_hour = 12;

    /* Note how pointer addition is used to skip the first 11
     * characters and printf is used to trim off terminating
     * characters.
     */
    printf( "12-hour time:\t\t\t\t%.8s %s\n",
       asctime( today ) + 11, ampm );

    /* Print additional time information. */
    _ftime( &tstruct );
    printf( "Plus milliseconds:\t\t\t%u\n", tstruct.millitm );
    printf( "Zone difference in seconds from UTC:\t%u\n",
             tstruct.timezone );
    printf( "Time zone name:\t\t\t\t%s\n", _tzname[0] );
    printf( "Daylight savings:\t\t\t%s\n",
             tstruct.dstflag ? "YES" : "NO" );

    /* Make time for noon on Christmas, 1993. */
    if( mktime( &xmas ) != (time_t)-1 )
   printf( "Christmas\t\t\t\t%s\n", asctime( &xmas ) );

    /* Use time structure to build a customized time string. */
    today = localtime( &ltime );

    /* Use strftime to build a customized time string. */
    strftime( tmpbuf, 128,
         "Today is %A, day %d of %B in the year %Y.\n", today );
    printf( tmpbuf );
}

Output

OS time:                                21:51:03
OS date:                                05/03/94
Time in seconds since UTC 1/1/70:       768027063
UNIX time and date:                     Tue May 03 21:51:03 1994
Coordinated universal time:             Wed May 04 04:51:03 1994
12-hour time:                           09:51:03 PM
Plus milliseconds:                      279
Zone difference in seconds from UTC:    480
Time zone name:
Daylight savings:                       YES
Christmas                               Sat Dec 25 12:00:00 1993

Today is Tuesday, day 03 of May in the year 1994.

Time Management Routines

See Also asctime, ctime, gmtime, localtime, mktime, time, _tzset


_strdup, _wcsdup, _mbsdup

Duplicate strings.

char *_strdup( const char *strSource );

wchar_t *_wcsdup( const wchar_t *strSource );

unsigned char *_mbsdup( const unsigned char *strSource );

Routine | Required Header | Compatibility
_strdup | <string.h> | Win 95, Win NT
_wcsdup | <string.h> or <wchar.h> | Win 95, Win NT
_mbsdup | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the storage location for the copied string or NULL if storage cannot be allocated.

Parameter

strSource

Null-terminated source string

Remarks

The _strdup function calls malloc to allocate storage space for a copy of strSource and then copies strSource to the allocated space.

_wcsdup and _mbsdup are wide-character and multibyte-character versions of _strdup. The arguments and return value of _wcsdup are wide-character strings; those of _mbsdup are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsdup | _strdup | _mbsdup | _wcsdup

Because _strdup calls malloc to allocate storage space for the copy of strSource, it is good practice always to release this memory by calling the free routine on the pointer returned by the call to _strdup.

Example

/* STRDUP.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char buffer[] = "This is the buffer text";
   char *newstring;
   printf( "Original: %s\n", buffer );
   newstring = _strdup( buffer );
   printf( "Copy:     %s\n", newstring );
   free( newstring );
}

Output

Original: This is the buffer text
Copy:     This is the buffer text

String Manipulation Routines

See Also memset, strcat, strcmp, strncat, strncmp, strncpy, _strnicmp, strrchr, strspn


strerror, _strerror

Get a system error message (strerror) or prints a user-supplied error message (_strerror).

char *strerror( int errnum );

char *_strerror( const char *strErrMsg );

Routine | Required Header | Compatibility
strerror | <string.h> | ANSI, Win 95, Win NT
_strerror | <string.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

strerror and _strerror return a pointer to the error-message string. Subsequent calls to strerror or _strerror can overwrite the string.

Parameters

errnum

Error number

strErrMsg

User-supplied message

Remarks

The strerror function maps errnum to an error-message string, returning a pointer to the string. Neither strerror nor _strerror actually prints the message: For that, you need to call an output function such as fprintf:

if (( _access( "datafile",2 )) == -1 )
   fprintf( stderr, strerror(NULL) );

If strErrMsg is passed as NULL, _strerror returns a pointer to a string containing the system error message for the last library call that produced an error. The error-message string is terminated by the newline character ('\n'). If strErrMsg is not equal to NULL, then _strerror returns a pointer to a string containing (in order) your string message, a colon, a space, the system error message for the last library call producing an error, and a newline character. Your string message can be, at most, 94 bytes long.

The actual error number for _strerror is stored in the variable errno. The system error messages are accessed through the variable _sys_errlist, which is an array of messages ordered by error number. _strerror accesses the appropriate error message by using the errno value as an index to the variable _sys_errlist. The value of the variable _sys_nerr is defined as the maximum number of elements in the _sys_errlist array. To produce accurate results, call _strerror immediately after a library routine returns with an error. Otherwise, subsequent calls to strerror or _strerror can overwrite the errno value.

_strerror is not part of the ANSI definition but is instead a Microsoft extension to it. Do not use it where portability is desired; for ANSI compatibility, use strerror instead.

Example

/* PERROR.C: This program attempts to open a file named
 * NOSUCHF.ILE. Because this file probably doesn't exist,
 * an error message is displayed. The same message is
 * created using perror, strerror, and _strerror.
 */

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

void main( void )
{
   int  fh;

   if( (fh = _open( "NOSUCHF.ILE", _O_RDONLY )) == -1 )
   {
      /* Three ways to create error message: */
      perror( "perror says open failed" );
      printf( "strerror says open failed: %s\n", strerror( errno ) );
      printf( _strerror( "_strerror says open failed" ) );
   }
   else
   {
      printf( "open succeeded on input file\n" );
      _close( fh );
   }
}

Output

perror says open failed: No such file or directory

strerror says open failed: No such file or directory
_strerror says open failed: No such file or directory

String Manipulation Routines

See Also clearerr, ferror, perror


strftime, wcsftime

Format a time string.

size_t strftime( char *strDest, size_t maxsize, const char *format, const struct tm *timeptr );

size_t wcsftime( wchar_t *strDest, size_t maxsize, const wchar_t *format, const struct tm *timeptr );

Routine | Required Header | Compatibility
strftime | <time.h> | ANSI, Win 95, Win NT
wcsftime | <time.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

strftime returns the number of characters placed in strDest if the total number of resulting characters, including the terminating null, is not more than maxsize. wcsftime returns the corresponding number of wide characters. Otherwise, the functions return 0, and the contents of strDest is indeterminate.

Parameters

strDest

Output string

maxsize

Maximum length of string

format

Format-control string

timeptr

tm data structure

Remarks

The strftime and wcsftime functions format the tm time value in timeptr according to the supplied format argument and store the result in the buffer strDest. At most, maxsize characters are placed in the string. For a description of the fields in the timeptr structure, see asctime. wcsftime is the wide-character equivalent of strftime; its string-pointer argument points to a wide-character string. These functions behave identically otherwise.

Note Prior to this version of Visual C++, the documentation described the format parameter of wcsftime as having the datatype const wchar_t *, but the actual implementation of the format datatype was const char *. In this version, the implementation of the format datatype has been updated to reflect the previous and current documentation, that is: const wchar_t *.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsftime | strftime | strftime | wcsftime

The format argument consists of one or more codes; as in printf, the formatting codes are preceded by a percent sign (%). Characters that do not begin with % are copied unchanged to strDest. The LC_TIME category of the current locale affects the output formatting of strftime.(For more information on LC_TIME, see setlocale.) The formatting codes for strftime are listed below:

%a

Abbreviated weekday name

%A

Full weekday name

%b

Abbreviated month name

%B

Full month name

%c

Date and time representation appropriate for locale

%d

Day of month as decimal number (01 – 31)

%H

Hour in 24-hour format (00 – 23)

%I

Hour in 12-hour format (01 – 12)

%j

Day of year as decimal number (001 – 366)

%m

Month as decimal number (01 – 12)

%M

Minute as decimal number (00 – 59)

%p

Current locale’s A.M./P.M. indicator for 12-hour clock

%S

Second as decimal number (00 – 59)

%U

Week of year as decimal number, with Sunday as first day of week (00 – 53)

%w

Weekday as decimal number (0 – 6; Sunday is 0)

%W

Week of year as decimal number, with Monday as first day of week (00 – 53)

%x

Date representation for current locale

%X

Time representation for current locale

%y

Year without century, as decimal number (00 – 99)

%Y

Year with century, as decimal number

%z, %Z

Time-zone name or abbreviation; no characters if time zone is unknown

%%

Percent sign

As in the printf function, the # flag may prefix any formatting code. In that case, the meaning of the format code is changed as follows.

Format Code | Meaning
%#a, %#A, %#b, %#B, %#p, %#X, %#z, %#Z, %#% | # flag is ignored.
%#c | Long date and time representation, appropriate for current locale. For example: “Tuesday, March 14, 1995, 12:41:29”.
%#x | Long date representation, appropriate to current locale. For example: “Tuesday, March 14, 1995”.
%#d, %#H, %#I, %#j, %#m, %#M, %#S, %#U, %#w, %#W, %#y, %#Y | Remove leading zeros (if any).

Example

/* TIMES.C illustrates various time and date functions including:
 *      time            _ftime          ctime       asctime
 *      localtime       gmtime          mktime      _tzset
 *      _strtime        _strdate        strftime
 *
 * Also the global variable:
 *      _tzname
 */

#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <string.h>

void main()
{
    char tmpbuf[128], ampm[] = "AM";
    time_t ltime;
    struct _timeb tstruct;
    struct tm *today, *gmt, xmas = { 0, 0, 12, 25, 11, 93 };

    /* Set time zone from TZ environment variable. If TZ is not set,
     * the operating system is queried to obtain the default value
     * for the variable.
     */
    _tzset();

    /* Display operating system-style date and time. */
    _strtime( tmpbuf );
    printf( "OS time:\t\t\t\t%s\n", tmpbuf );
    _strdate( tmpbuf );
    printf( "OS date:\t\t\t\t%s\n", tmpbuf );

    /* Get UNIX-style time and display as number and string. */
    time( &ltime );
    printf( "Time in seconds since UTC 1/1/70:\t%ld\n", ltime );
    printf( "UNIX time and date:\t\t\t%s", ctime( &ltime ) );

    /* Display UTC. */
    gmt = gmtime( &ltime );
    printf( "Coordinated universal time:\t\t%s", asctime( gmt ) );

    /* Convert to time structure and adjust for PM if necessary. */
    today = localtime( &ltime );
    if( today->tm_hour > 12 )
    {
   strcpy( ampm, "PM" );
   today->tm_hour -= 12;
    }
    if( today->tm_hour == 0 )  /* Adjust if midnight hour. */
   today->tm_hour = 12;

    /* Note how pointer addition is used to skip the first 11
     * characters and printf is used to trim off terminating
     * characters.
     */
    printf( "12-hour time:\t\t\t\t%.8s %s\n",
       asctime( today ) + 11, ampm );

    /* Print additional time information. */
    _ftime( &tstruct );
    printf( "Plus milliseconds:\t\t\t%u\n", tstruct.millitm );
    printf( "Zone difference in seconds from UTC:\t%u\n",
             tstruct.timezone );
    printf( "Time zone name:\t\t\t\t%s\n", _tzname[0] );
    printf( "Daylight savings:\t\t\t%s\n",
             tstruct.dstflag ? "YES" : "NO" );

    /* Make time for noon on Christmas, 1993. */
    if( mktime( &xmas ) != (time_t)-1 )
   printf( "Christmas\t\t\t\t%s\n", asctime( &xmas ) );

    /* Use time structure to build a customized time string. */
    today = localtime( &ltime );

    /* Use strftime to build a customized time string. */
    strftime( tmpbuf, 128,
         "Today is %A, day %d of %B in the year %Y.\n", today );
    printf( tmpbuf );
}

Output

OS time:                                21:51:03
OS date:                                05/03/94
Time in seconds since UTC 1/1/70:       768027063
UNIX time and date:                     Tue May 03 21:51:03 1994
Coordinated universal time:             Wed May 04 04:51:03 1994
12-hour time:                           09:51:03 PM
Plus milliseconds:                      279
Zone difference in seconds from UTC:    480
Time zone name:
Daylight savings:                       YES
Christmas                               Sat Dec 25 12:00:00 1993

Today is Tuesday, day 03 of May in the year 1994.

Locale Routines, Time Management Routines | String Manipulation Routines

See Also localeconv, setlocale, strcoll, _stricoll, strxfrm


_stricmp, _wcsicmp, _mbsicmp

Perform a lowercase comparison of strings.

int _stricmp( const char *string1, const char *string2 );

int _wcsicmp( const wchar_t *string1, const wchar_t *string2 );

int _mbsicmp( const unsigned char *string1, const unsigned char_t *string2 );

Routine | Required Header | Compatibility
_stricmp | <string.h> | Win 95, Win NT
_wcsicmp | <string.h> or <wchar.h> | Win 95, Win NT
_mbsicmp | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relation of string1 to string2 as follows.

Return Value | Description
< 0 | string1 less than string2
0 | string1 identical to string2
> 0 | string1 greater than string2

On an error, _mbsicmp returns _NLSCMPERROR, which is defined in STRING.H and MBSTRING.H.

Parameters

string1, string2

Null-terminated strings to compare

Remarks

The _stricmp function lexicographically compares lowercase versions of string1 and string2 and returns a value indicating their relationship. _stricmp differs from _stricoll in that the _stricmp comparison is not affected by locale, whereas the _stricoll comparison is according to the LC_COLLATE category of the current locale. For more information on the LC_COLLATE category, see setlocale.

The _strcmpi function is equivalent to _stricmp and is provided for backward compatibility only.

_wcsicmp and _mbsicmp are wide-character and multibyte-character versions of _stricmp. The arguments and return value of _wcsicmp are wide-character strings; those of _mbsicmp are multibyte-character strings. _mbsicmp recognizes multibyte-character sequences according to the current multibyte code page and returns _NLSCMPERROR on an error. (For more information, see Code Pages.) These three functions behave identically otherwise.

_wcsicmp and wcscmp behave identically except that wcscmp does not convert its arguments to lowercase before comparing them. _mbsicmp and _mbscmp behave identically except that _mbscmp does not convert its arguments to lowercase before comparing them.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsicmp | _stricmp | _mbsicmp | _wcsicmp

Example

/* STRCMP.C */

#include <string.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown dog jumps over the lazy fox";

void main( void )
{
   char tmp[20];
   int result;
   /* Case sensitive */
   printf( "Compare strings:\n\t%s\n\t%s\n\n", string1, string2 );
   result = strcmp( string1, string2 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "\tstrcmp:   String 1 is %s string 2\n", tmp );
   /* Case insensitive (could use equivalent _stricmp) */
   result = _stricmp( string1, string2 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "\t_stricmp:  String 1 is %s string 2\n", tmp );
}

Output

Compare strings:
   The quick brown dog jumps over the lazy fox
   The QUICK brown dog jumps over the lazy fox

   strcmp:   String 1 is greater than string 2
   _stricmp:  String 1 is equal to string 2

String Manipulation Routines

See Also memcmp, _memicmp, strcmp, strcoll Functions, strncmp, _strnicmp, strrchr, _strset, strspn


strlen, wcslen, _mbslen, _mbstrlen

Get the length of a string.

size_t strlen( const char *string );

size_t wcslen( const wchar_t *string );

size_t _mbslen( const unsigned char *string );

size_t _mbstrlen( const char *string );

Routine | Required Header | Compatibility
strlen | <string.h> | ANSI, Win 95, Win NT
wcslen | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbslen | <mbstring.h> | Win 95, Win NT
_mbstrlen | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the number of characters in string, excluding the terminal NULL. No return value is reserved to indicate an error.

Parameter

string

Null-terminated string

Remarks

Each of these functions returns the number of characters in string, not including the terminating null character. wcslen is a wide-character version of strlen; the argument of wcslen is a wide-character string. wcslen and strlen behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcslen | strlen | strlen | wcslen
_tcsclen | strlen | _mbslen | wcslen

_mbslen and _mbstrlen return the number of multibyte characters in a multibyte-character string. _mbslen recognizes multibyte-character sequences according to the multibyte code page currently in use; it does not test for multibyte-character validity. _mbstrlen tests for multibyte-character validity and recognizes multibyte-character sequences according to the LC_CTYPE category setting of the current locale. For more information about the LC_CTYPE category, see setlocale.

Example

/*  STRLEN.C */

#include <string.h>
#include <stdio.h>
#include <conio.h>
#include <dos.h>

void main( void )
{
   char buffer[61] = "How long am I?";
   int  len;
   len = strlen( buffer );
   printf( "'%s' is %d characters long\n", buffer, len );
}

Output

'How long am I?' is 14 characters long

String Manipulation Routines | Locale Routines

See Also setlocale, strcat, strcmp, strcoll Functions, strcpy, strrchr, _strset, strspn


_strlwr, _wcslwr, _mbslwr

Convert a string to lowercase.

char *_strlwr( char *string );

wchar_t *_wcslwr( wchar_t *string );

unsigned char *_mbslwr( unsigned char *string );

Routine | Required Header | Compatibility
_strlwr | <string.h> | Win 95, Win NT
_wcslwr | <string.h> or <wchar.h> | Win 95, Win NT
_mbslwr | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the converted string. Because the modification is done in place, the pointer returned is the same as the pointer passed as the input argument. No return value is reserved to indicate an error.

Parameter

string

Null-terminated string to convert to lowercase

Remarks

The _strlwr function converts any uppercase letters in string to lowercase as determined by the LC_CTYPE category setting of the current locale. Other characters are not affected. For more information on LC_CTYPE, see setlocale.

The _wcslwr and _mbslwr functions are wide-character and multibyte-character versions of _strlwr. The argument and return value of _wcslwr are wide-character strings; those of _mbslwr are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcslwr | _strlwr | _mbslwr | _wcslwr

Example

/* STRLWR.C: This program uses _strlwr and _strupr to create
 * uppercase and lowercase copies of a mixed-case string.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100] = "The String to End All Strings!";
   char *copy1, *copy2;
   copy1 = _strlwr( _strdup( string ) );
   copy2 = _strupr( _strdup( string ) );
   printf( "Mixed: %s\n", string );
   printf( "Lower: %s\n", copy1 );
   printf( "Upper: %s\n", copy2 );
}

Output

Mixed: The String to End All Strings!
Lower: the string to end all strings!
Upper: THE STRING TO END ALL STRINGS!

String Manipulation Routines | Locale Routines

See Also _strupr


strncat, wcsncat, _mbsncat

Append characters of a string.

char *strncat( char *strDest, const char *strSource, size_t count );

wchar_t *wcsncat( wchar_t *strDest, const wchar_t *strSource, size_t count );

unsigned char *_mbsncat( unsigned char *strDest, const unsigned char *strSource, size_t count);

Routine | Required Header | Compatibility
strncat | <string.h> | ANSI, Win 95, Win NT
wcsncat | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbsncat | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the destination string. No return value is reserved to indicate an error.

Parameters

strDest

Null-terminated destination string

strSource

Null-terminated source string

count

Number of characters to append

Remarks

The strncat function appends, at most, the first count characters of strSource to strDest. The initial character of strSource overwrites the terminating null character of strDest. If a null character appears in strSource before count characters are appended, strncat appends all characters from strSource, up to the null character. If count is greater than the length of strSource, the length of strSource is used in place of count. The resulting string is terminated with a null character. If copying takes place between strings that overlap, the behavior is undefined.

wcsncat and _mbsncat are wide-character and multibyte-character versions of strncat. The string arguments and return value of wcsncat are wide-character strings; those of _mbsncat are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncat | strncat | _mbsnbcat | wcsncat

Example

/* STRNCAT.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[80] = "This is the initial string!";
   char suffix[] = " extra text to add to the string...";
   /* Combine strings with no more than 19 characters of suffix: */
   printf( "Before: %s\n", string );
   strncat( string, suffix, 19 );
   printf( "After:  %s\n", string );
}

Output

Before: This is the initial string!
After:  This is the initial string! extra text to add

String Manipulation Routines

See Also _mbsnbcat, strcat, strcmp, strcpy, strncmp, strncpy, _strnicmp, strrchr, _strset, strspn


strncmp, wcsncmp, _mbsncmp

Compare characters of two strings.

int strncmp( const char *string1, const char *string2, size_t count );

int wcsncmp( const wchar_t *string1, const wchar_t *string2, size_t count );

int _mbsncmp( const unsigned char *string1, const unsigned char string2, size_t count );

Routine | Required Header | Compatibility
strncmp | <string.h> | ANSI, Win 95, Win NT
wcsncmp | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbsncmp | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relation of the substrings of string1 and string2 as follows.

Return Value | Description
< 0 | string1 substring less than string2 substring
0 | string1 substring identical to string2 substring
> 0 | string1 substring greater than string2 substring

On an error, _mbsncmp returns _NLSCMPERROR, which is defined in STRING.H and MBSTRING.H.

Parameters

string1, string2

Strings to compare

count

Number of characters to compare

Remarks

The strncmp function lexicographically compares, at most, the first count characters in string1 and string2 and returns a value indicating the relationship between the substrings. strncmp is a case-sensitive version of _strnicmp. Unlike strcoll, strncmp is not affected by locale. For more information on the LC_COLLATE category, see setlocale.

wcsncmp and _mbsncmp are wide-character and multibyte-character versions of strncmp. The arguments and return value of wcsncmp are wide-character strings; those of _mbsncmp are multibyte-character strings. _mbsncmp recognizes multibyte-character sequences according to the current multibyte code page and returns _NLSCMPERROR on an error. For more information, see Code Pages. These three functions behave identically otherwise. wcsncmp and _mbsncmp are case-sensitive versions of _wcsnicmp and _mbsnicmp.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsnccmp | strncmp | _mbsnbcmp | wcsncmp
_tcsncmp | strncmp | _mbsnbcmp | wcsncmp

Example

/* STRNCMP.C */
#include <string.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown fox jumps over the lazy dog";

void main( void )
{
   char tmp[20];
   int result;
   printf( "Compare strings:\n\t\t%s\n\t\t%s\n\n", string1, string2 );
   printf( "Function:\tstrncmp (first 10 characters only)\n" );
   result = strncmp( string1, string2 , 10 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
   printf( "Function:\tstrnicmp _strnicmp (first 10 characters only)\n" );
   result = _strnicmp( string1, string2, 10 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
}

Output

Compare strings:
      The quick brown dog jumps over the lazy fox
      The QUICK brown fox jumps over the lazy dog

Function:   strncmp (first 10 characters only)
Result:      String 1 is greater than string 2

Function:   _strnicmp (first 10 characters only)
Result:      String 1 is equal to string 2

String Manipulation Routines

See Also _mbsnbcmp, _mbsnbicmp, strcmp, strcoll Functions, _strnicmp, strrchr, _strset, strspn


strncpy, wcsncpy, _mbsncpy

Copy characters of one string to another.

char *strncpy( char *strDest, const char *strSource, size_t count );

wchar_t *wcsncpy( wchar_t *strDest, const wchar_t *strSource, size_t count );

unsigned char *_mbsncpy( unsigned char *strDest, const unsigned char *strSource, size_t count );

Routine | Required Header | Compatibility
strncpy | <string.h> | ANSI, Win 95, Win NT
wcsncpy | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbsncpy | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns strDest. No return value is reserved to indicate an error.

Parameters

strDest

Destination string

strSource

Source string

count

Number of characters to be copied

Remarks

The strncpy function copies the initial count characters of strSource to strDest and returns strDest. If count is less than or equal to the length of strSource, a null character is not appended automatically to the copied string. If count is greater than the length of strSource, the destination string is padded with null characters up to length count. The behavior of strncpy is undefined if the source and destination strings overlap.

wcsncpy and _mbsncpy are wide-character and multibyte-character versions of strncpy. The arguments and return value of wcsncpy and _mbsncpy vary accordingly. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncpy | strncpy | _mbsnbcpy | wcsncpy

Example

/* STRNCPY.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100] = "Cats are nice usually";
   printf ( "Before: %s\n", string );
   strncpy( string, "Dogs", 4 );
   strncpy( string + 9, "mean", 4 );
   printf ( "After:  %s\n", string );
}

Output

Before: Cats are nice usually
After:  Dogs are mean usually

String Manipulation Routines

See Also _mbsnbcpy, strcat, strcmp, strcpy, strncat, strncmp, _strnicmp, strrchr, _strset, strspn


_strnicmp, _wcsnicmp, _mbsnicmp

Compare characters of two strings without regard to case.

int _strnicmp( const char *string1, const char *string2, size_t count );

int _wcsnicmp( const wchar_t *string1, const wchar_t *string2, size_t count );

int _mbsnicmp( const unsigned char *string1, const unsigned char *string2, size_t count );

Routine | Required Header | Compatibility
_strnicmp | <string.h> | Win 95, Win NT
_wcsnicmp | <string.h> or <wchar.h> | Win 95, Win NT
_mbsnicmp | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The return value indicates the relationship between the substrings as follows.

Return Value | Description
< 0 | string1 substring less than string2 substring
0 | string1 substring identical to string2 substring
> 0 | string1 substring greater than string2 substring

On an error, _mbsnicmp returns _NLSCMPERROR, which is defined in STRING.H and MBSTRING.H.

Parameters

string1, string2

Null-terminated strings to compare

count

Number of characters to compare

Remarks

The _strnicmp function lexicographically compares, at most, the first count characters of string1 and string2. The comparison is performed without regard to case; _strnicmp is a case-insensitive version of strncmp. The comparison ends if a terminating null character is reached in either string before count characters are compared. If the strings are equal when a terminating null character is reached in either string before count characters are compared, the shorter string is lesser.

Two strings containing characters located between 'Z' and 'a' in the ASCII table ('[', '\', ']', '^', '_', and '`') compare differently, depending on their case. For example, the two strings "ABCDE" and "ABCD^" compare one way if the comparison is lowercase ("abcde" > "abcd^") and the other way ("ABCDE" < "ABCD^") if it is uppercase.

_wcsnicmp and _mbsnicmp are wide-character and multibyte-character versions of _strnicmp. The arguments and return value of _wcsnicmp are wide-character strings; those of _mbsnicmp are multibyte-character strings. _mbsnicmp recognizes multibyte-character sequences according to the current multibyte code page and returns _NLSCMPERROR on an error. For more information, see Code Pages. These three functions behave identically otherwise. These functions are not affected by the current locale setting.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsncicmp | _strnicmp | _mbsnbicmp | _wcsnicmp
_tcsnicmp | _strnicmp | _mbsnbicmp | _wcsnicmp

Example

/* STRNCMP.C */
#include <string.h>
#include <stdio.h>

char string1[] = "The quick brown dog jumps over the lazy fox";
char string2[] = "The QUICK brown fox jumps over the lazy dog";

void main( void )
{
   char tmp[20];
   int result;
   printf( "Compare strings:\n\t\t%s\n\t\t%s\n\n", string1, string2 );
   printf( "Function:\tstrncmp (first 10 characters only)\n" );
   result = strncmp( string1, string2 , 10 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
   printf( "Function:\tstrnicmp _strnicmp (first 10 characters only)\n" );
   result = _strnicmp( string1, string2, 10 );
   if( result > 0 )
      strcpy( tmp, "greater than" );
   else if( result < 0 )
      strcpy( tmp, "less than" );
   else
      strcpy( tmp, "equal to" );
   printf( "Result:\t\tString 1 is %s string 2\n\n", tmp );
}

Output

Compare strings:
      The quick brown dog jumps over the lazy fox
      The QUICK brown fox jumps over the lazy dog

Function:   strncmp (first 10 characters only)
Result:      String 1 is greater than string 2

Function:   _strnicmp (first 10 characters only)
Result:      String 1 is equal to string 2

String Manipulation Routines

See Also strcat, strcmp, strcpy, strncat, strncmp, strncpy, strrchr, _strset, strspn


_strnset, _wcsnset, _mbsnset

Initialize characters of a string to a given format.

char *_strnset( char *string, int c, size_t count );

wchar_t *_wcsnset( wchar_t *string, wchar_t c, size_t count );

unsigned char *_mbsnset( unsigned char *string, unsigned int c, size_t count );

Routine | Required Header | Compatibility
_strnset | <string.h> | Win 95, Win NT
_wcsnset | <string.h> or <wchar.h> | Win 95, Win NT
_mbsnset | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the altered string.

Parameters

string

String to be altered

c

Character setting

count

Number of characters to be set

Remarks

The _strnset function sets, at most, the first count characters of string to c (converted to char). If count is greater than the length of string, the length of string is used instead of count.

_wcsnset and _mbsnset are wide-character and multibyte-character versions of _strnset. The string arguments and return value of _wcsnset are wide-character strings; those of _mbsnset are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsnset | _strnset | _mbsnbset | _wcsnset

Example

/* STRNSET.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[15] = "This is a test";
   /* Set not more than 4 characters of string to be *'s */
   printf( "Before: %s\n", string );
   _strnset( string, '*', 4 );
   printf( "After:  %s\n", string );
}

Output

Before: This is a test
After:  **** is a test

String Manipulation Routines

See Also strcat, strcmp, strcpy, _strset


strpbrk, wcspbrk, _mbspbrk

Scan strings for characters in specified character sets.

char *strpbrk( const char *string, const char *strCharSet );

wchar_t *wcspbrk( const wchar_t *string, const wchar_t *strCharSet );

unsigned char *_mbspbrk( const unsigned char*string, const unsigned char *strCharSet );

Routine | Required Header | Compatibility
strpbrk | <string.h> | ANSI, Win 95, Win NT
wcspbrk | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbspbrk | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the first occurrence of any character from strCharSet in string, or a NULL pointer if the two string arguments have no characters in common.

Parameters

string

Null-terminated, searched string

strCharSet

Null-terminated character set

Remarks

The strpbrk function returns a pointer to the first occurrence of a character in string that belongs to the set of characters in strCharSet. The search does not include the terminating null character.

wcspbrk and _mbspbrk are wide-character and multibyte-character versions of strpbrk. The arguments and return value of wcspbrk are wide-character strings; those of _mbspbrk are multibyte-character strings. These three functions behave identically otherwise. _mbspbrk is similar to _mbscspn except that _mbspbrk returns a pointer rather than a value of type size_t.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcspbrk | strpbrk | _mbspbrk | wcspbrk

Example

/* STRPBRK.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100] = "The 3 men and 2 boys ate 5 pigs\n";
   char *result;
   /* Return pointer to first 'a' or 'b' in "string" */
   printf( "1: %s\n", string );
   result = strpbrk( string, "0123456789" );
   printf( "2: %s\n", result++ );
   result = strpbrk( result, "0123456789" );
   printf( "3: %s\n", result++ );
   result = strpbrk( result, "0123456789" );
   printf( "4: %s\n", result );
}

Output

1: The 3 men and 2 boys ate 5 pigs

2: 3 men and 2 boys ate 5 pigs

3: 2 boys ate 5 pigs

4: 5 pigs

String Manipulation Routines

See Also strcspn, strchr, strrchr


strrchr, wcsrchr, _mbsrchr

Scan a string for the last occurrence of a character.

char *strrchr( const char *string, int c );

char *wcsrchr( const wchar_t *string, int c );

int _mbsrchr( const unsigned char *string, unsigned int c );

Routine | Required Header | Compatibility
strrchr | <string.h> | ANSI, Win 95, Win NT
wcsrchr | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbsrchr | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the last occurrence of c in string, or NULL if c is not found.

Parameters

string

Null-terminated string to search

c

Character to be located

Remarks

The strrchr function finds the last occurrence of c (converted to char) in string. The search includes the terminating null character.

wcsrchr and _mbsrchr are wide-character and multibyte-character versions of strrchr. The arguments and return value of wcsrchr are wide-character strings; those of _mbsrchr are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsrchr | strrchr | _mbsrchr | wcsrchr

Example

/* STRCHR.C: This program illustrates searching for a character
 * with strchr (search forward) or strrchr (search backward).
 */

#include <string.h>
#include <stdio.h>

int  ch = 'r';

char string[] = "The quick brown dog jumps over the lazy fox";
char fmt1[] =   "         1         2         3         4         5";
char fmt2[] =   "12345678901234567890123456789012345678901234567890";

void main( void )
{
   char *pdest;
   int result;

   printf( "String to be searched: \n\t\t%s\n", string );
   printf( "\t\t%s\n\t\t%s\n\n", fmt1, fmt2 );
   printf( "Search char:\t%c\n", ch );

   /* Search forward. */
   pdest = strchr( string, ch );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\tfirst %c found at position %d\n\n",
              ch, result );
   else
      printf( "Result:\t%c not found\n" );

   /* Search backward. */
   pdest = strrchr( string, ch );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "Result:\tlast %c found at position %d\n\n", ch, result );
   else
      printf( "Result:\t%c not found\n" );
}

Output

String to be searched:
      The quick brown dog jumps over the lazy fox
               1         2         3         4         5
      12345678901234567890123456789012345678901234567890

Search char:   r
Result:   first r found at position 12

Result:   last r found at position 30

String Manipulation Routines

See Also strchr, strcspn, _strnicmp, strpbrk, strspn


_strrev, _wcsrev, _mbsrev

Reverse characters of a string.

char *_strrev( char *string );

wchar_t *_wcsrev( wchar_t *string );

unsigned char *_mbsrev( unsigned char *string );

Routine | Required Header | Compatibility
_strrev | <string.h> | Win 95, Win NT
_wcsrev | <string.h> or <wchar.h> | Win 95, Win NT
_mbsrev | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the altered string. No return value is reserved to indicate an error.

Parameter

string

Null-terminated string to reverse

Remarks

The _strrev function reverses the order of the characters in string. The terminating null character remains in place. _wcsrev and _mbsrev are wide-character and multibyte-character versions of _strrev. The arguments and return value of _wcsrev are wide-character strings; those of _mbsrev are multibyte-character strings. For _mbsrev, the order of bytes in each multibyte character in string is not changed. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsrev | _strrev | _mbsrev | _wcsrev

Example

/* STRREV.C: This program checks an input string to
 * see whether it is a palindrome: that is, whether
 * it reads the same forward and backward.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100];
   int result;

   printf( "Input a string and I will tell you if it is a palindrome:\n" );
   gets( string );

   /* Reverse string and compare (ignore case): */
   result = _stricmp( string, _strrev( _strdup( string ) ) );
   if( result == 0 )
      printf( "The string \"%s\" is a palindrome\n\n", string );
   else
      printf( "The string \"%s\" is not a palindrome\n\n", string );
}

Output

Input a string and I will tell you if it is a palindrome:
Able was I ere I saw Elba
The string "Able was I ere I saw Elba" is a palindrome

String Manipulation Routines

See Also strcpy, _strset


_strset, _wcsset, _mbsset

Set characters of a string to a character.

char *_strset( char *string, int c );

wchar_t *_wcsset( wchar_t *string, wchar_t c );

unsigned char *_mbsset( unsigned char *string, unsigned int c );

Routine | Required Header | Compatibility
_strset | <string.h> | Win 95, Win NT
_wcsset | <string.h> or <wchar.h> | Win 95, Win NT
_mbsset | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the altered string. No return value is reserved to indicate an error.

Parameters

string

Null-terminated string to be set

c

Character setting

Remarks

The _strset function sets all the characters of string to c (converted to char), except the terminating null character. _wcsset and _mbsset are wide-character and multibyte-character versions of _strset. The data types of the arguments and return values vary accordingly. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsset | _strset | _mbsset | _wcsset

Example

/* STRSET.C */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[] = "Fill the string with something";
   printf( "Before: %s\n", string );
   _strset( string, '*' );
   printf( "After:  %s\n", string );
}

Output

Before: Fill the string with something
After:  ******************************

String Manipulation Routines

See Also _mbsnbset, memset, strcat, strcmp, strcpy, _strnset


strspn, wcsspn, _mbsspn

Find the first substring.

size_t strspn( const char *string, const char *strCharSet );

size_t wcsspn( const wchar_t *string, const wchar_t *strCharSet );

size_t _mbsspn( const unsigned char *string, const unsigned char *strCharSet );

Routine | Required Header | Compatibility
strspn | <string.h> | ANSI, Win 95, Win NT
wcsspn | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbsspn | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

strspn, wcsspn, and _mbsspn return an integer value specifying the length of the substring in string that consists entirely of characters in strCharSet. If string begins with a character not in strCharSet, the function returns 0. No return value is reserved to indicate an error. For each of these routines, no return value is reserved to indicate an error.

Parameters

string

Null-terminated string to search

strCharSet

Null-terminated character set

Remarks

The strspn function returns the index of the first character in string that does not belong to the set of characters in strCharSet. The search does not include terminating null characters.

wcsspn and _mbsspn are wide-character and multibyte-character versions of strspn. The arguments of wcsspn are wide-character strings; those of _mbsspn are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsspn | strspn | _mbsspn | wcsspn

Example

/* STRSPN.C: This program uses strspn to determine
 * the length of the segment in the string "cabbage"
 * consisting of a's, b's, and c's. In other words,
 * it finds the first non-abc letter.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[] = "cabbage";
   int  result;
   result = strspn( string, "abc" );
   printf( "The portion of '%s' containing only a, b, or c "
           "is %d bytes long\n", string, result );
}

Output

The portion of 'cabbage' containing only a, b, or c is 5 bytes long

String Manipulation Routines

See Also _mbsspnp, strcspn, strncat, strncmp, strncpy, _strnicmp, strrchr


strstr, wcsstr, _mbsstr

Find a substring.

char *strstr( const char *string, const char *strCharSet );

wchar_t *wcsstr( const wchar_t *string, const wchar_t *strCharSet );

unsigned char *_mbsstr( const unsigned char *string, const unsigned char *strCharSet );

Routine | Required Header | Compatibility
strstr | <string.h> | ANSI, Win 95, Win NT
wcsstr | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbsstr | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the first occurrence of strCharSet in string, or NULL if strCharSet does not appear in string. If strCharSet points to a string of zero length, the function returns string.

Parameters

string

Null-terminated string to search

strCharSet

Null-terminated string to search for

Remarks

The strstr function returns a pointer to the first occurrence of strCharSet in string. The search does not include terminating null characters. wcsstr and _mbsstr are wide-character and multibyte-character versions of strstr. The arguments and return value of wcsstr are wide-character strings; those of _mbsstr are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsstr | strstr | _mbsstr | wcsstr

Example

/* STRSTR.C */

#include <string.h>
#include <stdio.h>

char str[] =    "lazy";
char string[] = "The quick brown dog jumps over the lazy fox";
char fmt1[] =   "         1         2         3         4         5";
char fmt2[] =   "12345678901234567890123456789012345678901234567890";

void main( void )
{
   char *pdest;
   int  result;
   printf( "String to be searched:\n\t%s\n", string );
   printf( "\t%s\n\t%s\n\n", fmt1, fmt2 );
   pdest = strstr( string, str );
   result = pdest - string + 1;
   if( pdest != NULL )
      printf( "%s found at position %d\n\n", str, result );
   else
      printf( "%s not found\n", str );
}

Output

String to be searched:
   The quick brown dog jumps over the lazy fox
            1         2         3         4         5
   12345678901234567890123456789012345678901234567890

lazy found at position 36

String Manipulation Routines

See Also strcspn, strcmp, strpbrk, strrchr, strspn


_strtime, _wstrtime

Copy the time to a buffer.

char *_strtime( char *timestr );

wchar_t *_wstrtime( wchar_t *timestr );

Routine | Required Header | Compatibility
_strtime | <time.h> | Win 95, Win NT
_wstrtime | <time.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the resulting character string timestr.

Parameter

timestr

Time string

Remarks

The _strtime function copies the current local time into the buffer pointed to by timestr. The time is formatted as hh:mm:ss where hh is two digits representing the hour in 24-hour notation, mm is two digits representing the minutes past the hour, and ss is two digits representing seconds. For example, the string 18:23:44 represents 23 minutes and 44 seconds past 6 P.M. The buffer must be at least 9 bytes long.

_wstrtime is a wide-character version of _strtime; the argument and return value of _wstrtime are wide-character strings. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tstrtime | _strtime | _strtime | _wstrtime

Example

/* STRTIME.C */

#include <time.h>
#include <stdio.h>

void main( void )
{
   char dbuffer [9];
   char tbuffer [9];
   _strdate( dbuffer );
   printf( "The current date is %s \n", dbuffer );
   _strtime( tbuffer );
   printf( "The current time is %s \n", tbuffer );
}

Output

The current date is 03/23/93
The current time is 13:40:40

Time Management Routines

See Also asctime, ctime, gmtime, localtime, mktime, time, _tzset


strtod, strtol, strtoul Functions

strtod, wcstod

strtol, wcstol

strtoul, wcstoul

Return Value

strtod returns the value of the floating-point number, except when the representation would cause an overflow, in which case the function returns +/–HUGE_VAL. The sign of HUGE_VAL matches the sign of the value that cannot be represented. strtod returns 0 if no conversion can be performed or an underflow occurs.

strtol returns the value represented in the string nptr, except when the representation would cause an overflow, in which case it returns LONG_MAX or LONG_MIN. strtoul returns the converted value, if any, or ULONG_MAX on overflow. Each of these functions returns 0 if no conversion can be performed.

wcstod, wcstol, and wcstoul return values analogously to strtod, strtol, and strtoul, respectively.

For all six functions in this group, errno is set to ERANGE if overflow or underflow occurs.

Parameters

nptr

Null-terminated string to convert

endptr

Pointer to character that stops scan

base

Number base to use

Remarks

The strtod, strtol, and strtoul functions convert nptr to a double-precision value, a long-integer value, or an unsigned long-integer value, respectively.

The input string nptr is a sequence of characters that can be interpreted as a numerical value of the specified type. Each function stops reading the string nptr at the first character it cannot recognize as part of a number. This may be the terminating null character. For strtol or strtoul, this terminating character can also be the first numeric character greater than or equal to base.

For all six functions in the strtod group, the current locale’s LC_NUMERIC category setting determines recognition of the radix character in nptr; for more information, see setlocale. If endptr is not NULL, a pointer to the character that stopped the scan is stored at the location pointed to by endptr. If no conversion can be performed (no valid digits were found or an invalid base was specified), the value of nptr is stored at the location pointed to by endptr.

strtod expects nptr to point to a string of the following form:

[whitespace] [sign] [digits] [.digits] [ {d | D | e | E}[sign]digits]

A whitespace may consist of space or tab characters, which are ignored; sign is either plus (+) or minus (–); and digits are one or more decimal digits. If no digits appear before the radix character, at least one must appear after the radix character. The decimal digits can be followed by an exponent, which consists of an introductory letter (d, D, e, or E) and an optionally signed integer. If neither an exponent part nor a radix character appears, a radix character is assumed to follow the last digit in the string. The first character that does not fit this form stops the scan.

The strtol and strtoul functions expect nptr to point to a string of the following form:

[whitespace] [{+ | –}] [0 [{ x | X }]] [digits]

If base is between 2 and 36, then it is used as the base of the number. If base is 0, the initial characters of the string pointed to by nptr are used to determine the base. If the first character is 0 and the second character is not 'x' or 'X', the string is interpreted as an octal integer; otherwise, it is interpreted as a decimal number. If the first character is '0' and the second character is 'x' or 'X', the string is interpreted as a hexadecimal integer. If the first character is '1' through '9', the string is interpreted as a decimal integer. The letters 'a' through 'z' (or 'A' through 'Z') are assigned the values 10 through 35; only letters whose assigned values are less than base are permitted. strtoul allows a plus (+) or minus (–) sign prefix; a leading minus sign indicates that the return value is negated.

wcstod, wcstol, and wcstoul are wide-character versions of strtod, strtol, and strtoul, respectively; the nptr argument to each of these wide-character functions is a wide-character string. Otherwise, each of these wide-character functions behaves identically to its single-byte–character counterpart.

Example

/* STRTOD.C: This program uses strtod to convert a
 * string to a double-precision value; strtol to
 * convert a string to long integer values; and strtoul
 * to convert a string to unsigned long-integer values.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char   *string, *stopstring;
   double x;
   long   l;
   int    base;
   unsigned long ul;
   string = "3.1415926This stopped it";
   x = strtod( string, &stopstring );
   printf( "string = %s\n", string );
   printf("   strtod = %f\n", x );
   printf("   Stopped scan at: %s\n\n", stopstring );
   string = "-10110134932This stopped it";
   l = strtol( string, &stopstring, 10 );
   printf( "string = %s", string );
   printf("   strtol = %ld", l );
   printf("   Stopped scan at: %s", stopstring );
   string = "10110134932";
   printf( "string = %s\n", string );
   /* Convert string using base 2, 4, and 8: */
   for( base = 2; base <= 8; base *= 2 )
   {
      /* Convert the string: */
      ul = strtoul( string, &stopstring, base );
      printf( "   strtol = %ld (base %d)\n", ul, base );
      printf( "   Stopped scan at: %s\n", stopstring );
   }
}

Output

string = 3.1415926This stopped it
   strtod = 3.141593
   Stopped scan at: This stopped it

string = -10110134932This stopped it   strtol = -2147483647   Stopped scan at: This stopped itstring = 10110134932
   strtol = 45 (base 2)
   Stopped scan at: 34932
   strtol = 4423 (base 4)
   Stopped scan at: 4932
   strtol = 2134108 (base 8)
   Stopped scan at: 932

Data Conversion Routines | Floating-Point Support Routines | Locale Routines

See Also atof, localeconv, setlocale


strtod, wcstod

Convert strings to a double-precision value.

double strtod( const char *nptr, char **endptr );

double wcstod( const wchar_t *nptr, wchar_t **endptr );

Each of these functions converts the input string nptr to a double.

Routine | Required Header | Compatibility
strtod | <stdlib.h> | ANSI, Win 95, Win NT
wcstod | <stdlib.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

strtod returns the value of the floating-point number, except when the representation would cause an overflow, in which case the function returns +/–HUGE_VAL. The sign of HUGE_VAL matches the sign of the value that cannot be represented. strtod returns 0 if no conversion can be performed or an underflow occurs.

wcstod returns values analogously to strtod. For both functions, errno is set to ERANGE if overflow or underflow occurs.

Parameters

nptr

Null-terminated string to convert

endptr

Pointer to character that stops scan

Remarks

The strtod function converts nptr to a double-precision value. strtod stops reading the string nptr at the first character it cannot recognize as part of a number. This may be the terminating null character. wcstod is a wide-character version of strtod; its nptr argument is a wide-character string. Otherwise these functions behave identically.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcstod | strtod | strtod | wcstod

The LC_NUMERIC category setting of the current locale determines recognition of the radix character in nptr; for more information, see setlocale. If endptr is not NULL, a pointer to the character that stopped the scan is stored at the location pointed to by endptr. If no conversion can be performed (no valid digits were found or an invalid base was specified), the value of nptr is stored at the location pointed to by endptr.

strtod expects nptr to point to a string of the following form:

[whitespace] [sign] [digits] [.digits] [ {d | D | e | E}[sign]digits]

A whitespace may consist of space and tab characters, which are ignored; sign is either plus (+) or minus (–); and digits are one or more decimal digits. If no digits appear before the radix character, at least one must appear after the radix character. The decimal digits can be followed by an exponent, which consists of an introductory letter (d, D, e, or E) and an optionally signed integer. If neither an exponent part nor a radix character appears, a radix character is assumed to follow the last digit in the string. The first character that does not fit this form stops the scan.

Example

/* STRTOD.C: This program uses strtod to convert a
 * string to a double-precision value; strtol to
 * convert a string to long integer values; and strtoul
 * to convert a string to unsigned long-integer values.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char   *string, *stopstring;
   double x;
   long   l;
   int    base;
   unsigned long ul;
   string = "3.1415926This stopped it";
   x = strtod( string, &stopstring );
   printf( "string = %s\n", string );
   printf("   strtod = %f\n", x );
   printf("   Stopped scan at: %s\n\n", stopstring );
   string = "-10110134932This stopped it";
   l = strtol( string, &stopstring, 10 );
   printf( "string = %s", string );
   printf("   strtol = %ld", l );
   printf("   Stopped scan at: %s", stopstring );
   string = "10110134932";
   printf( "string = %s\n", string );
   /* Convert string using base 2, 4, and 8: */
   for( base = 2; base <= 8; base *= 2 )
   {
      /* Convert the string: */
      ul = strtoul( string, &stopstring, base );
      printf( "   strtol = %ld (base %d)\n", ul, base );
      printf( "   Stopped scan at: %s\n", stopstring );
   }
}

Output

string = 3.1415926This stopped it
   strtod = 3.141593
   Stopped scan at: This stopped it

string = -10110134932This stopped it   strtol = -2147483647   Stopped scan at: This stopped itstring = 10110134932
   strtol = 45 (base 2)
   Stopped scan at: 34932
   strtol = 4423 (base 4)
   Stopped scan at: 4932
   strtol = 2134108 (base 8)
   Stopped scan at: 932

Data Conversion Routines | Floating-Point Support Routines | Locale Routines | strtod Functions Overview

See Also strtol, strtoul, atof, localeconv, setlocale


strtok, wcstok, _mbstok

Find the next token in a string.

char *strtok( char *strToken, const char *strDelimit );

wchar_t *wcstok( wchar_t *strToken, const wchar_t *strDelimit );

unsigned char *_mbstok( unsigned char*strToken, const unsigned char *strDelimit );

Routine | Required Header | Compatibility
strtok | <string.h> | ANSI, Win 95, Win NT
wcstok | <string.h> or <wchar.h> | ANSI, Win 95, Win NT
_mbstok | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

All of these functions return a pointer to the next token found in strToken. They return NULL when no more tokens are found. Each call modifies strToken by substituting a NULL character for each delimiter that is encountered.

Parameters

strToken

String containing token(s)

strDelimit

Set of delimiter characters

Remarks

The strtok function finds the next token in strToken. The set of characters in strDelimit specifies possible delimiters of the token to be found in strToken on the current call. wcstok and _mbstok are wide-character and multibyte-character versions of strtok. The arguments and return value of wcstok are wide-character strings; those of _mbstok are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcstok | strtok | _mbstok | wcstok

On the first call to strtok, the function skips leading delimiters and returns a pointer to the first token in strToken, terminating the token with a null character. More tokens can be broken out of the remainder of strToken by a series of calls to strtok. Each call to strtok modifies strToken by inserting a null character after the token returned by that call. To read the next token from strToken, call strtok with a NULL value for the strToken argument. The NULL strToken argument causes strtok to search for the next token in the modified strToken. The strDelimit argument can take any value from one call to the next so that the set of delimiters may vary.

Warning Each of these functions uses a static variable for parsing the string into tokens. If multiple or simultaneous calls are made to the same function, a high potential for data corruption and inaccurate results exists. Therefore, do not attempt to call the same function simultaneously for different strings and be aware of calling one of these function from within a loop where another routine may be called that uses the same function. However, calling this function simultaneously from multiple threads does not have undesirable effects.

Example

/* STRTOK.C: In this program, a loop uses strtok
 * to print all the tokens (separated by commas
 * or blanks) in the string named "string".
 */

#include <string.h>
#include <stdio.h>

char string[] = "A string\tof ,,tokens\nand some  more tokens";
char seps[]   = " ,\t\n";
char *token;

void main( void )
{
   printf( "%s\n\nTokens:\n", string );
   /* Establish string and get the first token: */
   token = strtok( string, seps );
   while( token != NULL )
   {
      /* While there are tokens in "string" */
      printf( " %s\n", token );
      /* Get next token: */
      token = strtok( NULL, seps );
   }
}

Output

A string   of ,,tokens
and some  more tokens

Tokens:
 A
 string
 of
 tokens
 and
 some
 more
 tokens

String Manipulation Routines

See Also strcspn, strspn, setlocale


strtol, wcstol

Convert strings to a long-integer value.

long strtol( const char *nptr, char **endptr, int base );

long wcstol( const wchar_t *nptr, wchar_t **endptr, int base );

Routine | Required Header | Compatibility
strtol | <stdlib.h> | ANSI, Win 95, Win NT
wcstol | <stdlib.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

strtol returns the value represented in the string nptr, except when the representation would cause an overflow, in which case it returns LONG_MAX or LONG_MIN. strtol returns 0 if no conversion can be performed. wcstol returns values analogously to strtol. For both functions, errno is set to ERANGE if overflow or underflow occurs.

Parameters

nptr

Null-terminated string to convert

endptr

Pointer to character that stops scan

base

Number base to use

Remarks

The strtol function converts nptr to a long. strtol stops reading the string nptr at the first character it cannot recognize as part of a number. This may be the terminating null character, or it may be the first numeric character greater than or equal to base.

wcstol is a wide-character version of strtol; its nptr argument is a wide-character string. Otherwise these functions behave identically.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcstol | strtol | strtol | wcstol

The current locale’s LC_NUMERIC category setting determines recognition of the radix character in nptr; for more information, see setlocale. If endptr is not NULL, a pointer to the character that stopped the scan is stored at the location pointed to by endptr. If no conversion can be performed (no valid digits were found or an invalid base was specified), the value of nptr is stored at the location pointed to by endptr.

strtol expects nptr to point to a string of the following form:

[whitespace] [{+ | –}] [0 [{ x | X }]] [digits]

A whitespace may consist of space and tab characters, which are ignored; digits are one or more decimal digits. The first character that does not fit this form stops the scan. If base is between 2 and 36, then it is used as the base of the number. If base is 0, the initial characters of the string pointed to by nptr are used to determine the base. If the first character is 0 and the second character is not 'x' or 'X', the string is interpreted as an octal integer; otherwise, it is interpreted as a decimal number. If the first character is '0' and the second character is 'x' or 'X', the string is interpreted as a hexadecimal integer. If the first character is '1' through '9', the string is interpreted as a decimal integer. The letters 'a' through 'z' (or 'A' through 'Z') are assigned the values 10 through 35; only letters whose assigned values are less than base are permitted.

Example

/* STRTOD.C: This program uses strtod to convert a
 * string to a double-precision value; strtol to
 * convert a string to long integer values; and strtoul
 * to convert a string to unsigned long-integer values.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char   *string, *stopstring;
   double x;
   long   l;
   int    base;
   unsigned long ul;
   string = "3.1415926This stopped it";
   x = strtod( string, &stopstring );
   printf( "string = %s\n", string );
   printf("   strtod = %f\n", x );
   printf("   Stopped scan at: %s\n\n", stopstring );
   string = "-10110134932This stopped it";
   l = strtol( string, &stopstring, 10 );
   printf( "string = %s", string );
   printf("   strtol = %ld", l );
   printf("   Stopped scan at: %s", stopstring );
   string = "10110134932";
   printf( "string = %s\n", string );
   /* Convert string using base 2, 4, and 8: */
   for( base = 2; base <= 8; base *= 2 )
   {
      /* Convert the string: */
      ul = strtoul( string, &stopstring, base );
      printf( "   strtol = %ld (base %d)\n", ul, base );
      printf( "   Stopped scan at: %s\n", stopstring );
   }
}

Output

string = 3.1415926This stopped it
   strtod = 3.141593
   Stopped scan at: This stopped it

string = -10110134932This stopped it   strtol = -2147483647   Stopped scan at: This stopped itstring = 10110134932
   strtol = 45 (base 2)
   Stopped scan at: 34932
   strtol = 4423 (base 4)
   Stopped scan at: 4932
   strtol = 2134108 (base 8)
   Stopped scan at: 932

Data Conversion Routines | Locale Routines | strtod Functions Overview

See Also strtod, strtoul, atof, localeconv, setlocale


strtoul, wcstoul

Convert strings to an unsigned long-integer value.

unsigned long strtoul( const char *nptr, char **endptr, int base );

unsigned long wcstoul( const wchar_t *nptr, wchar_t **endptr, int base );

Routine | Required Header | Compatibility
strtoul | <stdlib.h> | ANSI, Win 95, Win NT
wcstoul | <stdlib.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

strtoul returns the converted value, if any, or ULONG_MAX on overflow. strtoul returns 0 if no conversion can be performed. wcstoul returns values analogously to strtoul. For both functions, errno is set to ERANGE if overflow or underflow occurs.

Parameters

nptr

Null-terminated string to convert

endptr

Pointer to character that stops scan

base

Number base to use

Remarks

Each of these functions converts the input string nptr to an unsigned long.

strtoul stops reading the string nptr at the first character it cannot recognize as part of a number. This may be the terminating null character, or it may be the first numeric character greater than or equal to base. The LC_NUMERIC category setting of the current locale determines recognition of the radix character in nptr; for more information, see setlocale. If endptr is not NULL, a pointer to the character that stopped the scan is stored at the location pointed to by endptr. If no conversion can be performed (no valid digits were found or an invalid base was specified), the value of nptr is stored at the location pointed to by endptr.

wcstoul is a wide-character version of strtoul; its nptr argument is a wide-character string. Otherwise these functions behave identically.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcstoul | strtoul | strtoul | wcstoul

strtoul expects nptr to point to a string of the following form:

[whitespace] [{+ | –}] [0 [{ x | X }]] [digits]

A whitespace may consist of space and tab characters, which are ignored; digits are one or more decimal digits. The first character that does not fit this form stops the scan. If base is between 2 and 36, then it is used as the base of the number. If base is 0, the initial characters of the string pointed to by nptr are used to determine the base. If the first character is 0 and the second character is not 'x' or 'X', the string is interpreted as an octal integer; otherwise, it is interpreted as a decimal number. If the first character is '0' and the second character is 'x' or 'X', the string is interpreted as a hexadecimal integer. If the first character is '1' through '9', the string is interpreted as a decimal integer. The letters 'a' through 'z' (or 'A' through 'Z') are assigned the values 10 through 35; only letters whose assigned values are less than base are permitted. strtoul allows a plus (+) or minus (–) sign prefix; a leading minus sign indicates that the return value is negated.

Example

/* STRTOD.C: This program uses strtod to convert a
 * string to a double-precision value; strtol to
 * convert a string to long integer values; and strtoul
 * to convert a string to unsigned long-integer values.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char   *string, *stopstring;
   double x;
   long   l;
   int    base;
   unsigned long ul;
   string = "3.1415926This stopped it";
   x = strtod( string, &stopstring );
   printf( "string = %s\n", string );
   printf("   strtod = %f\n", x );
   printf("   Stopped scan at: %s\n\n", stopstring );
   string = "-10110134932This stopped it";
   l = strtol( string, &stopstring, 10 );
   printf( "string = %s", string );
   printf("   strtol = %ld", l );
   printf("   Stopped scan at: %s", stopstring );
   string = "10110134932";
   printf( "string = %s\n", string );
   /* Convert string using base 2, 4, and 8: */
   for( base = 2; base <= 8; base *= 2 )
   {
      /* Convert the string: */
      ul = strtoul( string, &stopstring, base );
      printf( "   strtol = %ld (base %d)\n", ul, base );
      printf( "   Stopped scan at: %s\n", stopstring );
   }
}

Output

string = 3.1415926This stopped it
   strtod = 3.141593
   Stopped scan at: This stopped it

string = -10110134932This stopped it   strtol = -2147483647   Stopped scan at: This stopped itstring = 10110134932
   strtol = 45 (base 2)
   Stopped scan at: 34932
   strtol = 4423 (base 4)
   Stopped scan at: 4932
   strtol = 2134108 (base 8)
   Stopped scan at: 932

Data Conversion Routines, Locale Routines | strtod Functions Overview

See Also strtod, strtol, atof, localeconv, setlocale


_strupr, _wcsupr, _mbsupr

Convert a string to uppercase.

char *_strupr( char *string );

wchar_t *_wcsupr( wchar_t *string );

unsigned char *_mbsupr( unsigned char *string );

Routine | Required Header | Compatibility
_strupr | <string.h> | Win 95, Win NT
_wcsupr | <string.h> or <wchar.h> | Win 95, Win NT
_mbsupr | <mbstring.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

These functions return a pointer to the altered string. Because the modification is done in place, the pointer returned is the same as the pointer passed as the input argument. No return value is reserved to indicate an error.

Parameter

string

String to capitalize

Remarks

The _strupr function converts, in place, each lowercase letter in string to uppercase. The conversion is determined by the LC_CTYPE category setting of the current locale. Other characters are not affected. For more information on LC_CTYPE, see setlocale.

_wcsupr and _mbsupr are wide-character and multibyte-character versions of _strupr. The argument and return value of _wcsupr are wide-character strings; those of _mbsupr are multibyte-character strings. These three functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsupr | _strupr | _mbsupr | _wcsupr

Example

/* STRLWR.C: This program uses _strlwr and _strupr to create
 * uppercase and lowercase copies of a mixed-case string.
 */

#include <string.h>
#include <stdio.h>

void main( void )
{
   char string[100] = "The String to End All Strings!";
   char *copy1, *copy2;
   copy1 = _strlwr( _strdup( string ) );
   copy2 = _strupr( _strdup( string ) );
   printf( "Mixed: %s\n", string );
   printf( "Lower: %s\n", copy1 );
   printf( "Upper: %s\n", copy2 );
}

Output

Mixed: The String to End All Strings!
Lower: the string to end all strings!
Upper: THE STRING TO END ALL STRINGS!

Locale Routines | String Manipulation Routines

See Also _strlwr


strxfrm, wcsxfrm

Transform a string based on locale-specific information.

size_t strxfrm( char *strDest, const char *strSource, size_t count );

size_t wcsxfrm( wchar_t *strDest, const wchar_t *strSource, size_t count );

Routine | Required Header | Compatibility
strxfrm | <string.h> | ANSI, Win 95, Win NT
wcsxfrm | <string.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns the length of the transformed string, not counting the terminating null character. If the return value is greater than or equal to count, the content of strDest is unpredictable. On an error, each of the functions sets errno and returns (size_t) – 1.

Parameters

strDest

Destination string

strSource

Source string

count

Maximum number of characters to place in strDest

Remarks

The strxfrm function transforms the string pointed to by strSource into a new collated form that is stored in strDest. No more than count characters, including the null character, are transformed and placed into the resulting string. The transformation is made using the current locale’s LC_COLLATE category setting. For more information on LC_COLLATE, see setlocale.

After the transformation, a call to strcmp with the two transformed strings yields results identical to those of a call to strcoll applied to the original two strings. As with strcoll and stricoll, strxfrm automatically handles multibyte-character strings as appropriate.

wcsxfrm is a wide-character version of strxfrm; the string arguments of wcsxfrm are wide-character pointers. For wcsxfrm, after the string transformation, a call to wcscmp with the two transformed strings yields results identical to those of a call to wcscoll applied to the original two strings. wcsxfrm and strxfrm behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tcsxfrm | strxfrm | strxfrm | wcsxfrm

In the “C” locale, the order of the characters in the character set (ASCII character set) is the same as the lexicographic order of the characters. However, in other locales, the order of characters in the character set may differ from the lexicographic character order. For example, in certain European locales, the character 'a' (value 0x61) precedes the character 'ä' (value 0xE4) in the character set, but the character 'ä' precedes the character 'a' lexicographically.

In locales for which the character set and the lexicographic character order differ, use strxfrm on the original strings and then strcmp on the resulting strings to produce a lexicographic string comparison according to the current locale’s LC_COLLATE category setting. Thus, to compare two strings lexicographically in the above locale, use strxfrm on the original strings, then strcmp on the resulting strings. Alternatively, you can use strcoll rather than strcmp on the original strings.

The value of the following expression is the size of the array needed to hold the strxfrm transformation of the source string:

1 + strxfrm( NULL, string, 0 )

In the “C” locale only, strxfrm is equivalent to the following:

strncpy( _string1, _string2, _count );
return( strlen( _string1 ) );

Data Conversion Routines, Locale Routines, String Manipulation | strcoll Functions

See Also localeconv, setlocale, strcmp, strncmp


_swab

Swaps bytes.

void _swab( char *src, char *dest, int n );

Routine | Required Header | Compatibility
_swab | <stdlib.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Parameters

src

Data to be copied and swapped

dest

Storage location for swapped data

n

Number of bytes to be copied and swapped

Remarks

The _swab function copies n bytes from src, swaps each pair of adjacent bytes, and stores the result at dest. The integer n should be an even number to allow for swapping. _swab is typically used to prepare binary data for transfer to a machine that uses a different byte order.

Example

/* SWAB.C illustrates:
 *      _swab
 */

#include <stdlib.h>
#include <stdio.h>

char from[] = "BADCFEHGJILKNMPORQTSVUXWZY";
char to[] =   "..........................";

void main()
{
    printf( "Before:\t%s\n\t%s\n\n", from, to );
    _swab( from, to, sizeof( from ) );
    printf( "After:\t%s\n\t%s\n\n", from, to );
}

Output

Before:   BADCFEHGJILKNMPORQTSVUXWZY
   ..........................

After:   BADCFEHGJILKNMPORQTSVUXWZY
   ABCDEFGHIJKLMNOPQRSTUVWXYZ

Buffer Manipulation Routines


system, _wsystem

Execute a command.

int system( const char *command );

int _wsystem( const wchar_t *command );

Routine | Required Header | Compatibility
system | <process.h> or <stdlib.h> | ANSI, Win 95, Win NT
_wsystem | <process.h> or <stdlib.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If command is NULL and the command interpreter is found, the function returns a nonzero value. If the command interpreter is not found, it returns 0 and sets errno to ENOENT. If command is not NULL, system returns the value that is returned by the command interpreter. It returns the value 0 only if the command interpreter returns the value 0. A return value of – 1 indicates an error, and errno is set to one of the following values:

E2BIG

Argument list (which is system-dependent) is too big.

ENOENT

Command interpreter cannot be found.

ENOEXEC

Command-interpreter file has invalid format and is not executable.

ENOMEM

Not enough memory is available to execute command; or available memory has been corrupted; or invalid block exists, indicating that process making call was not allocated properly.

Parameter

command

Command to be executed

Remarks

The system function passes command to the command interpreter, which executes the string as an operating-system command. system refers to the COMSPEC and PATH environment variables that locate the command-interpreter file (the file named CMD.EXE in Windows NT). If command is NULL, the function simply checks to see whether the command interpreter exists.

You must explicitly flush (using fflush or _flushall) or close any stream before calling system.

_wsystem is a wide-character version of system; the command argument to _wsystem is a wide-character string. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tsystem | system | system | _wsystem

Example

/* SYSTEM.C: This program uses
 * system to TYPE its source file.
 */

#include <process.h>

void main( void )
{
   system( "type system.c" );
}

Output

/* SYSTEM.C: This program uses
 * system to TYPE its source file.
 */
#include <process.h>
void main( void )
{
   system( "type system.c" );
}

Process and Environment Control Routines

See Also _exec Functions, exit, _flushall, _spawn Functions


tan, tanh

Calculate the tangent (tan) or hyperbolic tangent (tanh).

double tan( double x );

double tanh( double x );

Routine | Required Header | Compatibility
tan | <math.h> | ANSI, Win 95, Win NT
tanh | <math.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

tan returns the tangent of x. If x is greater than or equal to 263, or less than or equal to –263, a loss of significance in the result occurs, in which case the function generates a _TLOSS error and returns an indefinite (same as a quiet NaN). You can modify error handling with _matherr.

tanh returns the hyperbolic tangent of x. There is no error return.

Parameter

x

Angle in radians

Example

/* TAN.C:  This program displays the tangent of pi / 4
 * and the hyperbolic tangent of the result.
 */

#include <math.h>
#include <stdio.h>

void main( void )
{
   double pi = 3.1415926535;
   double x, y;

   x = tan( pi / 4 );
   y = tanh( x );
   printf( "tan( %f ) = %f\n", pi/4, x );
   printf( "tanh( %f ) = %f\n", x, y );
}

Output

tan( 0.785398 ) = 1.000000
tanh( 1.000000 ) = 0.761594

Floating-Point Support Routines | Long Double Routines

See Also acos, asin, atan, cos, sin


_tell, _telli64

Get the position of the file pointer.

long _tell( int handle );

__int64 _telli64( int handle );

Routine | Required Header | Compatibility
_tell | <io.h> | Win 95, Win NT
_telli64 | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

A return value of –1L indicates an error, and errno is set to EBADF to indicate an invalid file-handle argument. On devices incapable of seeking, the return value is undefined.

Parameter

handle

Handle referring to open file

Remarks

The _tell function gets the current position of the file pointer (if any) associated with the handle argument. The position is expressed as the number of bytes from the beginning of the file. For the _telli64 function, this value is expressed as a 64-bit integer.

Example

/* TELL.C:  This program uses _tell to tell the
 * file pointer position after a file read.
 */

#include <io.h>
#include <stdio.h>
#include <fcntl.h>

void main( void )
{
   int  fh;
   char buffer[500];

   if( (fh = _open( "tell.c", _O_RDONLY )) != -1 )
   {
      if( _read( fh, buffer, 500 ) > 0 )
         printf( "Current file position is: %d\n", _tell( fh ) );
      _close( fh );
   }
}

Output

Current file position is: 434

Low-level I/O Routines

See Also ftell, _lseek


_tempnam, _wtempnam, tmpnam, _wtmpnam

Create temporary filenames.

char *_tempnam( char *dir, char *prefix );

wchar_t *_wtempnam( wchar_t *dir, wchar_t *prefix );

char *tmpnam( char *string );

wchar_t *_wtmpnam( wchar_t *string );

Routine | Required Header | Compatibility
_tempnam | <stdio.h> | Win 95, Win NT
_wtempnam | <stdio.h> or <wchar.h> | Win 95, Win NT
tmpnam | <stdio.h> | ANSI, Win 95, Win NT
_wtmpnam | <stdio.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to the name generated, unless it is impossible to create this name or the name is not unique. If the name cannot be created or if a file with that name already exists, tmpnam and _tempnam return NULL. _tempnam and _wtempnam also return NULL if the file search fails.

Note The pointer returned by tmpnam points to an internal static buffer. free does not need to be called to deallocate this pointer.

Parameters

prefix

Filename prefix

dir

Target directory to be used if TMP not defined

string

Pointer to temporary name

Remarks

The tmpnam function generates a temporary filename that can be used to open a temporary file without overwriting an existing file.

This name is stored in string. If string is NULL, then tmpnam leaves the result in an internal static buffer. Thus any subsequent calls destroy this value. If string is not NULL, it is assumed to point to an array of at least L_tmpnam characters — or 2*L_tmpnam bytes. The value of L_tmpnam is defined in STDIO.H. The function generates unique filenames for up to TMP_MAX calls.

The character string that tmpnam creates consists of the path prefix, defined by the entry P_tmpdir in the file STDIO.H, followed by a sequence consisting of the digit characters '0' through '9'; the numerical value of this string is in the range 1 – 65,535. Changing the definitions of L_tmpnam or P_tmpdir in STDIO.H does not change the operation of tmpnam.

_tempnam creates a temporary filename for use in another directory. This filename is different from that of any existing file. The prefix argument is the prefix to the filename. _tempnam uses malloc to allocate space for the filename; the program is responsible for freeing this space when it is no longer needed. _tempnam looks for the file with the given name in the following directories, listed in order of precedence.

Directory Used | Conditions
Directory specified by TMP | TMP environment variable is set, and directory specified by TMP exists.
dir argument to _tempnam | TMP environment variable is not set, or directory specified by TMP does not exist.
P_tmpdir in STDIO.H | dir argument is NULL, or dir is name of nonexistent directory.
Current working directory | P_tmpdir does not exist.

_tempnam and tmpnam automatically handle multibyte-character string arguments as appropriate, recognizing multibyte-character sequences according to the OEM code page obtained from the operating system. _wtempnam is a wide-character version of _tempnam; the arguments and return value of _wtempnam are wide-character strings. _wtempnam and _tempnam behave identically except that _wtempnam does not handle multibyte-character strings. _wtmpnam is a wide-character version of tmpnam; the argument and return value of _wtmpnam are wide-character strings. _wtmpnam and tmpnam behave identically except that _wtmpnam does not handle multibyte-character strings.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_ttmpnam | tmpnam | tmpnam | _wtmpnam
_ttempnam | _tempnam | _tempnam | _wtempnam

Example

/* TEMPNAM.C: This program uses tmpnam to create a unique
 * filename in the current working directory, then uses
 * _tempnam to create a unique filename with a prefix of stq.
 */

#include <stdio.h>

void main( void )
{
   char *name1, *name2;

   /* Create a temporary filename for the current working directory: */
   if( ( name1 = tmpnam( NULL ) ) != NULL )
      printf( "%s is safe to use as a temporary file.\n", name1 );
   else
      printf( "Cannot create a unique filename\n" );

   /* Create a temporary filename in temporary directory with the
    * prefix "stq". The actual destination directory may vary
    * depending on the state of the TMP environment variable and
    * the global variable P_tmpdir.
    */
   if( ( name2 = _tempnam( "c:\\tmp", "stq" ) ) != NULL )
      printf( "%s is safe to use as a temporary file.\n", name2 );
   else
      printf( "Cannot create a unique filename\n" );
}

Output

\s5d. is safe to use as a temporary file.
C:\temp\stq2 is safe to use as a temporary file.

Stream I/O Routines

See Also _getmbcp, malloc, _setmbcp, tmpfile


terminate

Calls abort or a function you specify using set_terminate.

void terminate( void );

Routine | Required Header | Compatibility
terminate | <eh.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Remarks

The terminate function is used with C++ exception handling and is called in the following cases:

  • A matching catch handler cannot be found for a thrown C++ exception.

  • An exception is thrown by a destructor function during stack unwind.

  • The stack is corrupted after throwing an exception.

terminate calls abort by default. You can change this default by writing your own termination function and calling set_terminate with the name of your function as its argument. terminate calls the last function given as an argument to set_terminate. For more information, see Unhandled Exceptions.

Example

/* TERMINAT.CPP:
 */
#include <eh.h>
#include <process.h>
#include <iostream.h>

void term_func();

void main()
{

    int i = 10, j = 0, result;
    set_terminate( term_func );
    try
    {
        if( j == 0 )
            throw "Divide by zero!";
        else
            result = i/j;

    }
    catch( int )
    {
        cout << "Caught some integer exception.\n";
    }
    cout << "This should never print.\n";

}
void term_func()
{
    cout << "term_func() was called by terminate().\n";

    // ... cleanup tasks performed here

    // If this function does not exit, abort is called.

    exit(-1);
}

Output

term_func() was called by terminate().

Exception Handling Routines

See Also abort, _set_se_translator, set_terminate, set_unexpected, unexpected


time

Gets the system time.

time_t time( time_t *timer );

Routine | Required Header | Compatibility
time | <time.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

time returns the time in elapsed seconds. There is no error return.

Parameter

timer

Storage location for time

Remarks

The time function returns the number of seconds elapsed since midnight (00:00:00), January 1, 1970, coordinated universal time, according to the system clock. The return value is stored in the location given by timer. This parameter may be NULL, in which case the return value is not stored.

Example

/* TIMES.C illustrates various time and date functions including:
 *      time            _ftime          ctime       asctime
 *      localtime       gmtime          mktime      _tzset
 *      _strtime        _strdate        strftime
 *
 * Also the global variable:
 *      _tzname
 */

#include <time.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <string.h>

void main()
{
    char tmpbuf[128], ampm[] = "AM";
    time_t ltime;
    struct _timeb tstruct;
    struct tm *today, *gmt, xmas = { 0, 0, 12, 25, 11, 93 };

    /* Set time zone from TZ environment variable. If TZ is not set,
     * the operating system is queried to obtain the default value
     * for the variable.
     */
    _tzset();

    /* Display operating system-style date and time. */
    _strtime( tmpbuf );
    printf( "OS time:\t\t\t\t%s\n", tmpbuf );
    _strdate( tmpbuf );
    printf( "OS date:\t\t\t\t%s\n", tmpbuf );

    /* Get UNIX-style time and display as number and string. */
    time( &ltime );
    printf( "Time in seconds since UTC 1/1/70:\t%ld\n", ltime );
    printf( "UNIX time and date:\t\t\t%s", ctime( &ltime ) );

    /* Display UTC. */
    gmt = gmtime( &ltime );
    printf( "Coordinated universal time:\t\t%s", asctime( gmt ) );

    /* Convert to time structure and adjust for PM if necessary. */
    today = localtime( &ltime );
    if( today->tm_hour > 12 )
    {
   strcpy( ampm, "PM" );
   today->tm_hour -= 12;
    }
    if( today->tm_hour == 0 )  /* Adjust if midnight hour. */
   today->tm_hour = 12;

    /* Note how pointer addition is used to skip the first 11
     * characters and printf is used to trim off terminating
     * characters.
     */
    printf( "12-hour time:\t\t\t\t%.8s %s\n",
       asctime( today ) + 11, ampm );

    /* Print additional time information. */
    _ftime( &tstruct );
    printf( "Plus milliseconds:\t\t\t%u\n", tstruct.millitm );
    printf( "Zone difference in seconds from UTC:\t%u\n",
             tstruct.timezone );
    printf( "Time zone name:\t\t\t\t%s\n", _tzname[0] );
    printf( "Daylight savings:\t\t\t%s\n",
             tstruct.dstflag ? "YES" : "NO" );

    /* Make time for noon on Christmas, 1993. */
    if( mktime( &xmas ) != (time_t)-1 )
   printf( "Christmas\t\t\t\t%s\n", asctime( &xmas ) );

    /* Use time structure to build a customized time string. */
    today = localtime( &ltime );

    /* Use strftime to build a customized time string. */
    strftime( tmpbuf, 128,
         "Today is %A, day %d of %B in the year %Y.\n", today );
    printf( tmpbuf );
}

Output

OS time:                                21:51:03
OS date:                                05/03/94
Time in seconds since UTC 1/1/70:       768027063
UNIX time and date:                     Tue May 03 21:51:03 1994
Coordinated universal time:             Wed May 04 04:51:03 1994
12-hour time:                           09:51:03 PM
Plus milliseconds:                      279
Zone difference in seconds from UTC:    480
Time zone name:
Daylight savings:                       YES
Christmas                               Sat Dec 25 12:00:00 1993

Today is Tuesday, day 03 of May in the year 1994.

Time Management Routines

See Also asctime, _ftime, gmtime, localtime, _utime


tmpfile

Creates a temporary file.

FILE *tmpfile( void );

Routine | Required Header | Compatibility
tmpfile | <stdio.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, tmpfile returns a stream pointer. Otherwise, it returns a NULL pointer.

Remarks

The tmpfile function creates a temporary file and returns a pointer to that stream. If the file cannot be opened, tmpfile returns a NULL pointer. This temporary file is automatically deleted when the file is closed, when the program terminates normally, or when _rmtmp is called, assuming that the current working directory does not change. The temporary file is opened in w+b (binary read/write) mode.

Example

/* TMPFILE.C: This program uses tmpfile to create a
 * temporary file, then deletes this file with _rmtmp.
 */

#include <stdio.h>

void main( void )
{
   FILE *stream;
   char tempstring[] = "String to be written";
   int  i;

   /* Create temporary files. */
   for( i = 1; i <= 3; i++ )
   {
      if( (stream = tmpfile()) == NULL )
         perror( "Could not open new temporary file\n" );
      else
         printf( "Temporary file %d was created\n", i );
   }

   /* Remove temporary files. */
   printf( "%d temporary files deleted\n", _rmtmp() );
}

Output

Temporary file 1 was created
Temporary file 2 was created
Temporary file 3 was created
3 temporary files deleted

Stream I/O Routines

See Also _rmtmp, _tempnam


to Functions

Each of the to functions and its associated macro, if any, converts a single character to another character.

__toascii | toupper, _toupper, towupper
tolower, _tolower, towlower |

Remarks

The to functions and macro conversions are as follows.

Routine | Macro | Description
__toascii | __toascii | Converts c to ASCII character
tolower | tolower | Converts c to lowercase if appropriate
_tolower | _tolower | Converts c to lowercase
towlower | None | Converts c to corresponding wide-character lowercase letter
toupper | toupper | Converts c to uppercase if appropriate
_toupper | _toupper | Converts c to uppercase
towupper | None | Converts c to corresponding wide-character uppercase letter

To use the function versions of the to routines that are also defined as macros, either remove the macro definitions with #undef directives or do not include CTYPE.H. If you use the /Za compiler option, the compiler uses the function version of toupper or tolower. Declarations of the toupper and tolower functions are in STDLIB.H.

The __toascii routine sets all but the low-order 7 bits of c to 0, so that the converted value represents a character in the ASCII character set. If c already represents an ASCII character, c is unchanged.

The tolower and toupper routines:

  • Are dependent on the LC_CTYPE category of the current locale (tolower calls isupper and toupper calls islower).

  • Convert c if c represents a convertible letter of the appropriate case in the current locale and the opposite case exists for that locale. Otherwise, c is unchanged.

The _tolower and _toupper routines:

  • Are locale-independent, much faster versions of tolower and toupper.

  • Can be used only when isascii(c) and either isupper(c) or islower(c), respectively, are true.

  • Have undefined results if c is not an ASCII letter of the appropriate case for converting.

The towlower and towupper functions return a converted copy of c if and only if both of the following conditions are true. Otherwise, c is unchanged.

  • c is a wide character of the appropriate case (that is, for which iswupper or iswlower, respectively, is true).

  • There is a corresponding wide character of the target case (that is, for which iswlower or iswupper, respectively, is true).

Example

/* TOUPPER.C: This program uses toupper and tolower to
 * analyze all characters between 0x0 and 0x7F. It also
 * applies _toupper and _tolower to any code in this
 * range for which these functions make sense.
 */

#include <conio.h>
#include <ctype.h>
#include <string.h>

char msg[] = "Some of THESE letters are Capitals\r\n";
char *p;

void main( void )
{
   _cputs( msg );

   /* Reverse case of message. */
   for( p = msg; p < msg + strlen( msg ); p++ )
   {
      if( islower( *p ) )
         _putch( _toupper( *p ) );
      else if( isupper( *p ) )
         _putch( _tolower( *p ) );
      else
         _putch( *p );
   }
}

Output

Some of THESE letters are Capitals
sOME OF these LETTERS ARE cAPITALS

Data Conversion Routines | Locale Routines

See Also is Routines


__toascii

Converts characters.

int __toascii( int c );

Routine | Required Header | Compatibility
__toascii | <ctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

__toascii converts a copy of c if possible, and returns the result. There is no return value reserved to indicate an error.

Parameter

c

Character to convert

Remarks

The __toascii routine converts the given character to an ASCII character.

Data Conversion Routines

See Also is Routines, to Functions Overview

Example

/* TOUPPER.C: This program uses toupper and tolower to
 * analyze all characters between 0x0 and 0x7F. It also
 * applies _toupper and _tolower to any code in this
 * range for which these functions make sense.
 */

#include <conio.h>
#include <ctype.h>
#include <string.h>

char msg[] = "Some of THESE letters are Capitals\r\n";
char *p;

void main( void )
{
   _cputs( msg );

   /* Reverse case of message. */
   for( p = msg; p < msg + strlen( msg ); p++ )
   {
      if( islower( *p ) )
         _putch( _toupper( *p ) );
      else if( isupper( *p ) )
         _putch( _tolower( *p ) );
      else
         _putch( *p );
   }
}

Output

Some of THESE letters are Capitals
sOME OF these LETTERS ARE cAPITALS


tolower, _tolower, towlower

Convert character to lowercase.

int tolower( int c );

int _tolower( int c );

int towlower( wint_t c );

Routine | Required Header | Compatibility
tolower | <stdlib.h> and <ctype.h> | ANSI, Win 95, Win NT
_tolower | <ctype.h> | Win 95, Win NT
towlower | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines converts a copy of c, if possible, and returns the result. There is no return value reserved to indicate an error.

Parameter

c

Character to convert

Remarks

Each of these routines converts a given uppercase letter to a lowercase letter if possible and appropriate.

Data Conversion Routines

See Also is Routines, to Functions Overview

Example

/* TOUPPER.C: This program uses toupper and tolower to
 * analyze all characters between 0x0 and 0x7F. It also
 * applies _toupper and _tolower to any code in this
 * range for which these functions make sense.
 */

#include <conio.h>
#include <ctype.h>
#include <string.h>

char msg[] = "Some of THESE letters are Capitals\r\n";
char *p;

void main( void )
{
   _cputs( msg );

   /* Reverse case of message. */
   for( p = msg; p < msg + strlen( msg ); p++ )
   {
      if( islower( *p ) )
         _putch( _toupper( *p ) );
      else if( isupper( *p ) )
         _putch( _tolower( *p ) );
      else
         _putch( *p );
   }
}

Output

Some of THESE letters are Capitals
sOME OF these LETTERS ARE cAPITALS


toupper _toupper, towupper

Convert character to uppercase.

int toupper( int c );

int _toupper( int c );

int towupper( wint_t c );

Routine | Required Header | Compatibility
toupper | <stdlib.h> and <ctype.h> | ANSI, Win 95, Win NT
_toupper | <ctype.h> | Win 95, Win NT
towupper | <ctype.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these routines converts a copy of c, if possible, and returns the result.

If c is a wide character for which iswlower is true and there is a corresponding wide character for which iswupper is true, towupper returns the corresponding wide character; otherwise, towupper returns c unchanged.

There is no return value reserved to indicate an error.

Parameter

c

Character to convert

Remarks

Each of these routines converts a given lowercase letter to an uppercase letter if possible and appropriate.

Data Conversion Routines

See Also is Routines, to Functions Overview

Example

/* TOUPPER.C: This program uses toupper and tolower to
 * analyze all characters between 0x0 and 0x7F. It also
 * applies _toupper and _tolower to any code in this
 * range for which these functions make sense.
 */

#include <conio.h>
#include <ctype.h>
#include <string.h>

char msg[] = "Some of THESE letters are Capitals\r\n";
char *p;

void main( void )
{
   _cputs( msg );

   /* Reverse case of message. */
   for( p = msg; p < msg + strlen( msg ); p++ )
   {
      if( islower( *p ) )
         _putch( _toupper( *p ) );
      else if( isupper( *p ) )
         _putch( _tolower( *p ) );
      else
         _putch( *p );
   }
}

Output

Some of THESE letters are Capitals
sOME OF these LETTERS ARE cAPITALS


towctrans

Transforms a wide character.

wint_t towctrans( wint_t c, wctrans_t category );

Routine | Required Header | Compatibility
towctrans | <wctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCP.LIB | Single thread static library, retail version
LIBCPMT.LIB | Multithread static library, retail version
MSVCPRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

The transformation of the character c, using the transform in category.

Remarks

The value of category must have been returned by an earlier successful call to wctrans.

Data Conversion Routines


_tzset

Sets time environment variables.

void _tzset( void );

Routine | Required Header | Compatibility
_tzset | <time.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Remarks

The _tzset function uses the current setting of the environment variable TZ to assign values to three global variables: _daylight, _timezone, and _tzname. These variables are used by the _ftime and localtime functions to make corrections from coordinated universal time (UTC) to local time, and by the time function to compute UTC from system time. Use the following syntax to set the TZ environment variable:

set TZ=tzn[+ | –]hh[:mm[:ss] ][dzn]

tzn

Three-letter time-zone name, such as PST. You must specify the correct offset from local time to UTC.

hh

Difference in hours between UTC and local time. Optionally signed.

mm

Minutes. Separated from hh by a colon (:).

ss

Seconds. Separated from mm by a colon (:).

dzn

Three-letter daylight-saving-time zone such as PDT. If daylight saving time is never in effect in the locality, set TZ without a value for dzn. The C run-time library assumes the United States’s rules for implementing the calculation of Daylight Saving Time (DST).

For example, to set the TZ environment variable to correspond to the current time zone in Germany, you can use one of the following statements:

set TZ=GST-1GDT
set TZ=GST+1GDT

These strings use GST to indicate German standard time, assume that Germany is one hour ahead of UTC, and assume that daylight savings time is in effect.

If the TZ value is not set, _tzset attempts to use the time zone information specified by the operating system. Under Windows NT and Windows 95, this information is specified in the Control Panel’s Date/Time application. If _tzset cannot obtain this information, it uses PST8PDT by default, which signifies the Pacific time zone.

Based on the TZ environment variable value, the following values are assigned to the global variables _daylight, _timezone, and _tzname when _tzset is called:

Global Variable | Description | Default Value
_daylight | Nonzero value if a daylight-saving-time zone is specified in TZ setting; otherwise, 0 | 1
_timezone | Difference in seconds between UTC and local time. | 28800 (28800 seconds equals 8 hours)
_tzname[0] | String value of time-zone name from TZ environmental variable; empty if TZ has not been set | PST
_tzname[1] | String value of daylight-saving-time zone; empty if daylight-saving-time zone is omitted from TZ environmental variable | PDT

The default values shown in the preceding table for _daylight and the _tzname array correspond to “PST8PDT.” If the DST zone is omitted from the TZ environmental variable, the value of _daylight is 0 and the _ftime, gmtime, and localtime functions return 0 for their DST flags.

Example

/* TZSET.C: This program first sets up the time zone by
 * placing the variable named TZ=EST5 in the environment
 * table. It then uses _tzset to set the global variables
 * named _daylight, _timezone, and _tzname.
 */

#include <time.h>
#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   if( _putenv( "TZ=EST5EDT" ) == -1 )
   {
      printf( "Unable to set TZ\n" );
      exit( 1 );
   }
   else
   {
      _tzset();
      printf( "_daylight = %d\n", _daylight );
      printf( "_timezone = %ld\n", _timezone );
      printf( "_tzname[0] = %s\n", _tzname[0] );
   }
   exit( 0 );
}

Output

_daylight = 1
_timezone = 18000
_tzname[0] = EST

Time Management Routines

See Also asctime, _ftime, gmtime, localtime, time, _utime


_ultoa, _ultow

Convert an unsigned long integer to a string.

char *_ultoa( unsigned long value, char *string, int radix );

wchar_t *_ultow( unsigned long value, wchar_t *string, int radix );

Routine | Required Header | Compatibility
_ultoa | <stdlib.h> | Win 95, Win NT
_ultow | <stdlib.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns a pointer to string. There is no error return.

Parameters

value

Number to be converted

string

String result

radix

Base of value

Remarks

The _ultoa function converts value to a null-terminated character string and stores the result (up to 33 bytes) in string. No overflow checking is performed. radix specifies the base of value; radix must be in the range 2 – 36. _ultow is a wide-character version of _ultoa.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_ultot | _ultoa | _ultoa | _ultow

Example

/* ITOA.C: This program converts integers of various
 * sizes to strings in various radixes.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char buffer[20];
   int  i = 3445;
   long l = -344115L;
   unsigned long ul = 1234567890UL;

   _itoa( i, buffer, 10 );
   printf( "String of integer %d (radix 10): %s\n", i, buffer );
   _itoa( i, buffer, 16 );
   printf( "String of integer %d (radix 16): 0x%s\n", i, buffer );
   _itoa( i, buffer, 2  );
   printf( "String of integer %d (radix 2): %s\n", i, buffer );

   _ltoa( l, buffer, 16 );
   printf( "String of long int %ld (radix 16): 0x%s\n", l,
                                                    buffer );

   _ultoa( ul, buffer, 16 );
   printf( "String of unsigned long %lu (radix 16): 0x%s\n", ul,
                                                    buffer );
}

Output

String of integer 3445 (radix 10): 3445
String of integer 3445 (radix 16): 0xd75
String of integer 3445 (radix 2): 110101110101
String of long int -344115 (radix 16): 0xfffabfcd
String of unsigned long 1234567890 (radix 16): 0x499602d2

Data Conversion Routines

See Also _itoa, _ltoa


_umask

Sets the default file-permission mask.

int _umask( int pmode );

Routine | Required Header | Compatibility
_umask | <io.h> and <sys/stat.h> and <sys/types.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_umask returns the previous value of pmode. There is no error return.

Parameter

pmode

Default permission setting

Remarks

The _umask function sets the file-permission mask of the current process to the mode specified by pmode. The file-permission mask modifies the permission setting of new files created by _creat, _open, or _sopen. If a bit in the mask is 1, the corresponding bit in the file’s requested permission value is set to 0 (disallowed). If a bit in the mask is 0, the corresponding bit is left unchanged. The permission setting for a new file is not set until the file is closed for the first time.

The argument pmode is a constant expression containing one or both of the manifest constants _S_IREAD and _S_IWRITE, defined in SYS\STAT.H. When both constants are given, they are joined with the bitwise-OR operator ( | ). If the pmode argument is _S_IREAD, reading is not allowed (the file is write-only). If the pmode argument is _S_IWRITE, writing is not allowed (the file is read-only). For example, if the write bit is set in the mask, any new files will be read-only. Note that with MS-DOS, Windows NT, and Windows 95, all files are readable; it is not possible to give write-only permission. Therefore, setting the read bit with _umask has no effect on the file’s modes.

Example

/* UMASK.C: This program uses _umask to set
 * the file-permission mask so that all future
 * files will be created as read-only files.
 * It also displays the old mask.
 */

#include <sys/stat.h>
#include <sys/types.h>
#include <io.h>
#include <stdio.h>

void main( void )
{
   int oldmask;

   /* Create read-only files: */
   oldmask = _umask( _S_IWRITE );
   printf( "Oldmask = 0x%.4x\n", oldmask );
}

Output

Oldmask = 0x0000

File Handling Routines | Low-level I/O Routines

See Also _chmod, _creat, _mkdir, _open


unexpected

Calls terminate or function you specify using set_unexpected.

void unexpected( void );

Routine | Required Header | Compatibility
unexpected | <eh.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

None

Remarks

The unexpected routine is not used with the current implemenation of C++ exception handling. unexpected calls terminate by default. You can change this default behavior by writing a custom termination function and calling set_unexpected with the name of your function as its argument. unexpected calls the last function given as an argument to set_unexpected.

Exception Handling Routines

See Also abort, _set_se_translator, set_terminate, set_unexpected, terminate


ungetc, ungetwc

Pushes a character back onto the stream.

int ungetc( int c, FILE *stream );

wint_t ungetwc( wint_t c, FILE *stream );

Routine | Required Header | Compatibility
ungetc | <stdio.h> | ANSI, Win 95, Win NT
ungetwc | <stdio.h> or <wchar.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, each of these functions returns the character argument c. If c cannot be pushed back or if no character has been read, the input stream is unchanged and ungetc returns EOF; ungetwc returns WEOF.

Parameters

c

Character to be pushed

stream

Pointer to FILE structure

Remarks

The ungetc function pushes the character c back onto stream and clears the end-of-file indicator. The stream must be open for reading. A subsequent read operation on stream starts with c. An attempt to push EOF onto the stream using ungetc is ignored.

Characters placed on the stream by ungetc may be erased if fflush, fseek, fsetpos, or rewind is called before the character is read from the stream. The file-position indicator will have the value it had before the characters were pushed back. The external storage corresponding to the stream is unchanged. On a successful ungetc call against a text stream, the file-position indicator is unspecified until all the pushed-back characters are read or discarded. On each successful ungetc call against a binary stream, the file-position indicator is decremented; if its value was 0 before a call, the value is undefined after the call.

Results are unpredictable if ungetc is called twice without a read or file-positioning operation between the two calls. After a call to fscanf, a call to ungetc may fail unless another read operation (such as getc) has been performed. This is because fscanf itself calls ungetc.

ungetwc is a wide-character version of ungetc. However, on each successful ungetwc call against a text or binary stream, the value of the file-position indicator is unspecified until all pushed-back characters are read or discarded.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_ungettc | ungetc | ungetc | ungetwc

Example

/* UNGETC.C: This program first converts a character
 * representation of an unsigned integer to an integer. If
 * the program encounters a character that is not a digit,
 * the program uses ungetc to replace it in the  stream.
 */

#include <stdio.h>
#include <ctype.h>

void main( void )
{
   int ch;
   int result = 0;

   printf( "Enter an integer: " );

   /* Read in and convert number: */
   while( ((ch = getchar()) != EOF) && isdigit( ch ) )
      result = result * 10 + ch - '0';    /* Use digit. */
   if( ch != EOF )
      ungetc( ch, stdin );                /* Put nondigit back. */
   printf( "Number = %d\nNextcharacter in stream = '%c'",
            result, getchar() );
}

Output

Enter an integer: 521a
Number = 521
Nextcharacter in stream = 'a'

Stream I/O Routines

See Also getc, putc


_ungetch

Pushes back the last charcter read from the console.

int _ungetch( int c );

Routine | Required Header | Compatibility
_ungetch | <conio.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_ungetch returns the character c if it is successful. A return value of EOF indicates an error.

Parameter

c

Character to be pushed

Remarks

The _ungetch function pushes the character c back to the console, causing c to be the next character read by _getch or _getche. _ungetch fails if it is called more than once before the next read. The c argument may not be EOF.

Example

/* UNGETCH.C: In this program, a white-space delimited
 * token is read from the keyboard. When the program
 * encounters a delimiter, it uses _ungetch to replace
 * the character in the keyboard buffer.
 */

#include <conio.h>
#include <ctype.h>
#include <stdio.h>

void main( void )
{
   char buffer[100];
   int count = 0;
   int ch;
   ch = _getche();
   while( isspace( ch ) )      /* Skip preceding white space. */
      ch = _getche();
   while( count < 99 )         /* Gather token. */
   {
      if( isspace( ch ) )      /* End of token. */
         break;
      buffer[count++] = (char)ch;
      ch = _getche();
   }
   _ungetch( ch );            /* Put back delimiter. */
   buffer[count] = '\0';      /* Null terminate the token. */
   printf( "\ntoken = %s\n", buffer );
}

Output

White
token = White

Console and Port I/O Routines

See Also _cscanf, _getch


_unlink, _wunlink

Delete a file.

int _unlink( const char *filename );

int _wunlink( const wchar_t *filename );

Routine | Required Header | Compatibility
_unlink | <io.h> and <stdio.h> | Win 95, Win NT
_wunlink | <io.h> or <wchar.h> | Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if successful. Otherwise, the function returns –1 and sets errno to EACCES, which means the path specifies a read-only file, or to ENOENT, which means the file or path is not found or the path specified a directory.

Parameter

filename

Name of file to remove

Remarks

The _unlink function deletes the file specified by filename. _wunlink is a wide-character version of _unlink; the filename argument to _wunlink is a wide-character string. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tunlink | _unlink | _unlink | _wunlink

Example

/* UNLINK.C: This program uses _unlink to delete UNLINK.OBJ. */

#include <stdio.h>

void main( void )
{
   if( _unlink( "unlink.obj" ) == -1 )
      perror( "Could not delete 'UNLINK.OBJ'" );
   else
      printf( "Deleted 'UNLINK.OBJ'\n" );
}

Output

Deleted 'UNLINK.OBJ'

File Handling Routines

See Also _close, remove


_utime, _wutime

Set the file modification time.

int _utime( unsigned char *filename, struct _utimbuf *times );

int _wutime( wchar_t *filename, struct _utimbuf *times );

Routine | Required Headers | Optional Headers | Compatibility
_utime | <sys/utime.h> | <errno.h> | Win 95, Win NT
_wutime | <utime.h> or <wchar.h> | <errno.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each of these functions returns 0 if the file-modification time was changed. A return value of –1 indicates an error, in which case errno is set to one of the following values:

EACCES

Path specifies directory or read-only file

EINVAL

Invalid times argument

EMFILE

Too many open files (the file must be opened to change its modification time)

ENOENT

Path or filename not found

Parameters

filename

Path or filename

times

Pointer to stored time values

Remarks

The _utime function sets the modification time for the file specified by filename. The process must have write access to the file in order to change the time. Under Windows NT and Windows 95, you can change the access time and the modication time in the _utimbuf structure. If times is a NULL pointer, the modification time is set to the current local time. Otherwise, times must point to a structure of type _utimbuf, defined in SYS\UTIME.H.

The _utimbuf structure stores file access and modification times used by _utime to change file-modification dates. The structure has the following fields, which are both of type time_t:

actime

Time of file access

modtime

Time of file modification

_utime is identical to _futime except that the filename argument of _utime is a filename or a path to a file, rather than a handle to an open file.

_wutime is a wide-character version of _utime; the filename argument to _wutime is a wide-character string. These functions behave identically otherwise.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_tutime | _utime | _utime | _wutime

Example

/* UTIME.C: This program uses _utime to set the
 * file-modification time to the current time.
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/utime.h>

void main( void )
{
   /* Show file time before and after. */
   system( "dir utime.c" );
   if( _utime( "utime.c", NULL ) == -1 )
      perror( "_utime failed\n" );
   else
      printf( "File time modified\n" );
   system( "dir utime.c" );
}

Output

 Volume in drive C is ALDONS
 Volume Serial Number is 0E17-1702

 Directory of C:\dolphin\crt\code

05/03/94  10:00p                   451 utime.c
               1 File(s)            451 bytes
                             83,320,832 bytes free
 Volume in drive C is ALDONS
 Volume Serial Number is 0E17-1702

 Directory of C:\dolphin\crt\code

05/03/94  10:00p                   451 utime.c
               1 File(s)            451 bytes
                             83,320,832 bytes free
File time modified

Time Management Routines

See Also asctime, ctime, _fstat, _ftime, _futime, gmtime, localtime, _stat, time


va_arg, va_end, va_start

Access variable-argument lists.

type va_arg( va_list arg_ptr, type );

void va_end( va_list arg_ptr );

void va_start( va_list arg_ptr ); (UNIX version)

void va_start( va_list arg_ptr, prev_param ); (ANSI version)

Routine | Required Header | Optional Headers | Compatibility
va_arg | <stdio.h> and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT
va_end | <stdio.h> and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT
va_start | <stdio.h> and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT

1 Required for UNIX V compatibility.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

va_arg returns the current argument; va_start and va_end do not return values.

Parameters

type

Type of argument to be retrieved

arg_ptr

Pointer to list of arguments

prev_param

Parameter preceding first optional argument (ANSI only)

Remarks

The va_arg, va_end, and va_start macros provide a portable way to access the arguments to a function when the function takes a variable number of arguments. Two versions of the macros are available: The macros defined in STDARG.H conform to the ANSI C standard, and the macros defined in VARARGS.H are compatible with the UNIX System V definition. The macros are:

va_alist

Name of parameter to called function (UNIX version only)

va_arg

Macro to retrieve current argument

va_dcl

Declaration of va_alist (UNIX version only)

va_end

Macro to reset arg_ptr

va_list

typedef for pointer to list of arguments defined in STDIO.H

va_start

Macro to set arg_ptr to beginning of list of optional arguments (UNIX version only)

Both versions of the macros assume that the function takes a fixed number of required arguments, followed by a variable number of optional arguments. The required arguments are declared as ordinary parameters to the function and can be accessed through the parameter names. The optional arguments are accessed through the macros in STDARG.H or VARARGS.H, which set a pointer to the first optional argument in the argument list, retrieve arguments from the list, and reset the pointer when argument processing is completed.

The ANSI C standard macros, defined in STDARG.H, are used as follows:

  • All required arguments to the function are declared as parameters in the usual way. va_dcl is not used with the STDARG.H macros.

  • va_start sets arg_ptr to the first optional argument in the list of arguments passed to the function. The argument arg_ptr must have va_list type. The argument prev_param is the name of the required parameter immediately preceding the first optional argument in the argument list. If prev_param is declared with the register storage class, the macro’s behavior is undefined. va_start must be used before va_arg is used for the first time.

  • va_arg retrieves a value of type from the location given by arg_ptr and increments arg_ptr to point to the next argument in the list, using the size of type to determine where the next argument starts. va_arg can be used any number of times within the function to retrieve arguments from the list.

  • After all arguments have been retrieved, va_end resets the pointer to NULL.

The UNIX System V macros, defined in VARARGS.H, operate somewhat differently:

  • Any required arguments to the function can be declared as parameters in the usual way.

  • The last (or only) parameter to the function represents the list of optional arguments. This parameter must be named va_alist (not to be confused with va_list, which is defined as the type of va_alist).

  • va_dcl appears after the function definition and before the opening left brace of the function. This macro is defined as a complete declaration of the va_alist parameter, including the terminating semicolon; therefore, no semicolon should follow va_dcl.

  • Within the function, va_start sets arg_ptr to the beginning of the list of optional arguments passed to the function. va_start must be used before va_arg is used for the first time. The argument arg_ptr must have va_list type.

  • va_arg retrieves a value of type from the location given by arg_ptr and increments arg_ptr to point to the next argument in the list, using the size of type to determine where the next argument starts. va_arg can be used any number of times within the function to retrieve the arguments from the list.

  • After all arguments have been retrieved, va_end resets the pointer to NULL.

Example

/* VA.C: The program below illustrates passing a variable
 * number of arguments using the following macros:
 *      va_start            va_arg              va_end
 *      va_list             va_dcl (UNIX only)
 */

#include <stdio.h>
#define ANSI            /* Comment out for UNIX version     */
#ifdef ANSI             /* ANSI compatible version          */
#include <stdarg.h>
int average( int first, ... );
#else                   /* UNIX compatible version          */
#include <varargs.h>
int average( va_list );
#endif

void main( void )
{
   /* Call with 3 integers (-1 is used as terminator). */
   printf( "Average is: %d\n", average( 2, 3, 4, -1 ) );

   /* Call with 4 integers. */
   printf( "Average is: %d\n", average( 5, 7, 9, 11, -1 ) );

   /* Call with just -1 terminator. */
   printf( "Average is: %d\n", average( -1 ) );
}

/* Returns the average of a variable list of integers. */
#ifdef ANSI             /* ANSI compatible version    */
int average( int first, ... )
{
   int count = 0, sum = 0, i = first;
   va_list marker;

   va_start( marker, first );     /* Initialize variable arguments. */
   while( i != -1 )
   {
      sum += i;
      count++;
      i = va_arg( marker, int);
   }
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#else       /* UNIX compatible version must use old-style definition.  */
int average( va_alist )
va_dcl
{
   int i, count, sum;
   va_list marker;

   va_start( marker );            /* Initialize variable arguments. */
   for( sum = count = 0; (i = va_arg( marker, int)) != -1; count++ )
      sum += i;
   va_end( marker );              /* Reset variable arguments.      */
   return( sum ? (sum / count) : 0 );
}
#endif

Output

Average is: 3
Average is: 8
Average is: 0

Argument Access Routines

See Also vfprintf


vprintf Functions

Each of the vprintf functions takes a pointer to an argument list, then formats and writes the given data to a particular destination.

vfprintf, vfwprintf | _vsnprintf, _vsnwprintf
vprintf, vwprintf | vsprintf, vswprintf

Remarks

The vprintf functions are similar to their counterpart functions as listed in the following table. However, each vprintf function accepts a pointer to an argument list, whereas each of the counterpart functions accepts an argument list.

These functions format data for output to destinations as follows.

Function | Counterpart Function | Output Destination
vfprintf | fprintf | stream
vfwprintf | fwprintf | stream
vprintf | printf | stdout
vwprintf | wprintf | stdout
vsprintf | sprintf | memory pointed to by buffer
vswprintf | swprintf | memory pointed to by buffer
_vsnprintf | _snprintf | memory pointed to by buffer
_vsnwprintf | _snwprintf | memory pointed to by buffer

The argptr argument has type va_list, which is defined in VARARGS.H and STDARG.H. The argptr variable must be initialized by va_start, and may be reinitialized by subsequent va_arg calls; argptr then points to the beginning of a list of arguments that are converted and transmitted for output according to the corresponding specifications in the format argument. format has the same form and function as the format argument for printf. None of these functions invokes va_end. For a more complete description of each vprintf function, see the description of its counterpart function as listed in the preceding table.

_vsnprintf differs from vsprintf in that it writes no more than count bytes to buffer.

vfwprintf, _vsnwprintf, vswprintf, and vwprintf are wide-character versions of vfprintf, _vsnprintf, vsprintf, and vprintf, respectively; in each of these wide-character functions, buffer and format are wide-character strings. Otherwise, each wide-character function behaves identically to its SBCS counterpart function.

For vsprintf, vswprintf, _vsnprintf and _vsnwprintf, if copying occurs between strings that overlap, the behavior is undefined.

Stream I/O Routines

See Also fprintf, printf, sprintf, va_arg


vfprintf, vfwprintf

Write formatted output using a pointer to a list of arguments.

int vfprintf( FILE *stream, const char *format, va_list argptr );

int vfwprintf( FILE *stream, const wchar_t *format, va_list argptr );

Routine | Required Header | Optional Headers | Compatibility
vfprintf | <stdio.h> and <stdarg.h> | <varargs.h>1 | ANSI, Win 95
vfwprintf | <stdio.h> or <wchar.h>, and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT

1 Required for UNIX V compatibility.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

vfprintf and vfwprintf return the number of characters written, not including the terminating null character, or a negative value if an output error occurs.

Parameters

stream

Pointer to FILE structure

format

Format specification

argptr

Pointer to list of arguments

For more information, see Format Specifications.

Remarks

Each of these functions takes a pointer to an argument list, then formats and writes the given data to stream.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_vftprintf | vfprintf | vfprintf | vfwprintf

Stream I/O Routines | vprintf Functions Overview

See Also fprintf, printf, sprintf, va_arg


vprintf, vwprintf

Write formatted output using a pointer to a list of arguments.

int vprintf( const char *format, va_list argptr );

int vwprintf( const wchar_t *format, va_list argptr );

Routine | Required Header | Optional Headers | Compatibility
vprintf | <stdio.h> and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT
vwprintf | <stdio.h> or <wchar.h>, and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT

1 Required for UNIX V compatibility.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

vprintf and vwprintf return the number of characters written, not including the terminating null character, or a negative value if an output error occurs.

Parameters

format

Format specification

argptr

Pointer to list of arguments

Remarks

Each of these functions takes a pointer to an argument list, then formats and writes the given data to stdout.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_vtprintf | vprintf | vprintf | vwprintf

Stream I/O Routines | vprintf Functions Overview

See Also fprintf, printf, sprintf, va_arg


_vsnprintf, _vsnwprintf

Write formatted output using a pointer to a list of arguments.

int _vsnprintf( char *buffer, size_t count, const char *format, va_list argptr );

int _vsnwprintf( wchar_t *buffer, size_t count, const wchar_t *format, va_list argptr );

Routine | Required Header | Optional Headers | Compatibility
_vsnprintf | <stdio.h> and <stdarg.h> | <varargs.h>1 | Win 95, Win NT
_vsnwprintf | <stdio.h> or <wchar.h>, and <stdarg.h> | <varargs.h>1 | Win 95, Win NT

1 Required for UNIX V compatibility.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

_vsnprintf and _vsnwprintf return the number of characters written, not including the terminating null character, or a negative value if an output error occurs. For _vsnprintf, if the number of bytes to write exceeds buffer, then count bytes are written and –1 is returned.

Parameters

buffer

Storage location for output

count

Maximum number of characters to write

format

Format specification

argptr

Pointer to list of arguments

Remarks

Each of these functions takes a pointer to an argument list, then formats and writes the given data to the memory pointed to by buffer.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_vsntprintf | _vsnprintf | _vsnprintf | _vsnwprintf

Stream I/O Routines | vprintf Functions Overview

See Also fprintf, printf, sprintf, va_arg


vsprintf, vswprintf

Write formatted output using a pointer to a list of arguments.

int vsprintf( char *buffer, const char *format, va_list argptr );

int vswprintf( wchar_t *buffer, const wchar_t *format, va_list argptr );

Routine | Required Header | Optional Headers | Compatibility
vsprintf | <stdio.h> and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT
vswprintf | <stdio.h> or <wchar.h>, and <stdarg.h> | <varargs.h>1 | ANSI, Win 95, Win NT

1 Required for UNIX V compatibility.

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

vsprintf and vswprintf return the number of characters written, not including the terminating null character, or a negative value if an output error occurs. For vswprintf, a negative value is also returned if count or more wide characters are requested to be written.

Parameters

buffer

Storage location for output

format

Format specification

argptr

Pointer to list of arguments

count

Maximum number of bytes to write

Remarks

Each of these functions takes a pointer to an argument list, then formats and writes the given data to the memory pointed to by buffer.

Generic-Text Routine Mappings

TCHAR.H Routine | _UNICODE & _MBCS Not Defined | _MBCS Defined | _UNICODE Defined
_vstprintf | vsprintf | vsprintf | vswprintf

Stream I/O Routines | vprintf Functions Overview

See Also fprintf, printf, sprintf, va_arg


wcstombs

Converts a sequence of wide characters to a corresponding sequence of multibyte characters.

size_t wcstombs( char *mbstr, const wchar_t *wcstr, size_t count );

Routine | Required Header | Compatibility
wcstombs | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If wcstombs successfully converts the multibyte string, it returns the number of bytes written into the multibyte output string, excluding the terminating NULL (if any). If the mbstr argument is NULL, wcstombs returns the required size of the destination string. If wcstombs encounters a wide character it cannot be convert to a multibyte character, it returns –1 cast to type size_t.

Parameters

mbstr

The address of a sequence of multibyte characters

wcstr

The address of a sequence of wide characters

count

The maximum number of bytes that can be stored in the multibyte output string

Remarks

The wcstombs function converts the wide-character string pointed to by wcstr to the corresponding multibyte characters and stores the results in the mbstr array. The count parameter indicates the maximum number of bytes that can be stored in the multibyte output string (that is, the size of mbstr). In general, it is not known how many bytes will be required when converting a wide-character string. Some wide characters will require only one byte in the output string; others require two. If there are two bytes in the multibyte output string for every wide character in the input string (including the wide character NULL), the result is guaranteed to fit.

If wcstombs encounters the wide-character null character (L'\0') either before or when count occurs, it converts it to an 8-bit 0 and stops. Thus, the multibyte character string at mbstr is null-terminated only if wcstombs encounters a wide-character null character during conversion. If the sequences pointed to by wcstr and mbstr overlap, the behavior of wcstombs is undefined.

If the mbstr argument is NULL, wcstombs returns the required size of the destination string.

Example

/* WCSTOMBS.C illustrates the behavior of the wcstombs function. */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int      i;
   char    *pmbbuf   = (char *)malloc( MB_CUR_MAX );
   wchar_t *pwchello = L"Hello, world.";

   printf( "Convert wide-character string:\n" );
   i = wcstombs( pmbbuf, pwchello, MB_CUR_MAX );
   printf( "\tCharacters converted: %u\n", i );
   printf( "\tMultibyte character: %s\n\n", pmbbuf );
}

Output

Convert wide-character string:
   Characters converted: 1
   Multibyte character: H

Data Conversion Routines | Locale Routines

See Also mblen, mbstowcs, mbtowc, wctomb, WideCharToMultiByte


wctomb

Converts a wide character to the corresponding multibyte character.

int wctomb( char *mbchar, wchar_t wchar );

Routine | Required Header | Compatibility
wctomb | <stdlib.h> | ANSI, Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If wctomb converts the wide character to a multibyte character, it returns the number of bytes (which is never greater than MB_CUR_MAX) in the wide character. If wchar is the wide-character null character (L'\0'), wctomb returns 1. If the conversion is not possible in the current locale, wctomb returns –1.

Parameters

mbchar

The address of a multibyte character

wchar

A wide character

Remarks

The wctomb function converts its wchar argument to the corresponding multibyte character and stores the result at mbchar. You can call the function from any point in any program.

Example

/* WCTOMB.CPP illustrates the behavior of the wctomb function */

#include <stdio.h>
#include <stdlib.h>

void main( void )
{
   int i;
   wchar_t wc = L'a';
   char *pmbnull = NULL;
   char *pmb = (char *)malloc( sizeof( char ) );

   printf( "Convert a wide character:\n" );
   i = wctomb( pmb, wc );
   printf( "\tCharacters converted: %u\n", i );
   printf( "\tMultibyte character: %.1s\n\n", pmb );

   printf( "Attempt to convert when target is NULL:\n" );
   i = wctomb( pmbnull, wc );
   printf( "\tCharacters converted: %u\n", i );
   printf( "\tMultibyte character: %.1s\n", pmbnull );
}

Output

Convert a wide character:
   Characters converted: 1
   Multibyte character: a

Attempt to convert when target is NULL:
   Characters converted: 0
   Multibyte character: (

Data Conversion Routines | Locale Routines

See Also mblen, mbstowcs, mbtowc, wcstombs, WideCharToMultiByte


wctrans

Determines a mapping from one set of wide-character codes to another.

wctrans_t wctrans(const char *property );

Routine | Required Header | Compatibility
wctrans | <wctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCP.LIB | Single thread static library, retail version
LIBCPMT.LIB | Multithread static library, retail version
MSVCPRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If the LC_CTYPE category of the current locale does not define a mapping whose name matches the property string property, the function returns zero. Otherwise, it returns a nonzero value suitable for use as the second argument to a subsequent call to towctrans.

Parameters

property property string

Remarks

This function determines a mapping from one set of wide-character codes to another.

The following pairs of calls have the same behavior in all locales (but an implementation can define additional mappings even in the "C" locale):

tolower( c ) same as towctrans( c, wctrans("towlower" ) )

towupper( c ) same as towctrans( c, wctrans( "toupper" ) )

Data Conversion Routines

See Also setlocale


wctype

Determines a classification rule for wide-character codes.

wctype_t wctype( const char * property );

Routine | Required Header | Compatibility
wctype | <wctype.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBCP.LIB | Single thread static library, retail version
LIBCPMT.LIB | Multithread static library, retail version
MSVCPRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If the LC_CTYPE category of the current locale does not define a classification rule whose name matches the property string property, the function returns zero. Otherwise, it returns a nonzero value suitable for use as the second argument to a subsequent call to towctrans.

Parameters

property property string

Remarks

The function determines a classification rule for wide-character codes. The following pairs of calls have the same behavior in all locales (but an implementation can define additional classification rules even in the "C" locale):

iswalnum( c ) same as iswctype( c, wctype( "alnum" ) )

iswalpha( c ) same as iswctype( c, wctype( "alpha" ) )

iswcntrl( c ) same as iswctype( c, wctype( "cntrl" ) )

iswdigit( c ) same as iswctype( c, wctype( "digit" ) )

iswgraph( c ) same as iswctype( c, wctype( "graph" ) )

iswlower( c ) same as iswctype( c, wctype( "lower" ) )

iswprint( c ) same as iswctype( c, wctype( "print" ) )

iswpunct( c ) same as iswctype( c, wctype( "punct" ) )

iswspace( c ) same as iswctype( c, wctype( "space" ) )

iswupper( c ) same as iswctype( c, wctype( "upper" ) )

iswxdigit( c ) same as iswctype( c, wctype( "xdigit" ) )

Data Conversion Routines

See Also setlocale


_write

Writes data to a file.

int _write( int handle, const void *buffer, unsigned int count );

Routine | Required Header | Compatibility
_write | <io.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

If successful, _write returns the number of bytes actually written. If the actual space remaining on the disk is less than the size of the buffer the function is trying to write to the disk, _write fails and does not flush any of the buffer’s contents to the disk. A return value of –1 indicates an error. In this case, errno is set to one of two values: EBADF, which means the file handle is invalid or the file is not opened for writing, or ENOSPC, which means there is not enough space left on the device for the operation.

If the file is opened in text mode, each linefeed character is replaced with a carriage return – linefeed pair in the output. The replacement does not affect the return value.

Parameters

handle

Handle of file into which data is written

buffer

Data to be written

count

Number of bytes

Remarks

The _write function writes count bytes from buffer into the file associated with handle. The write operation begins at the current position of the file pointer (if any) associated with the given file. If the file is open for appending, the operation begins at the current end of the file. After the write operation, the file pointer is increased by the number of bytes actually written.

When writing to files opened in text mode, _write treats a CTRL+Z character as the logical end-of-file. When writing to a device, _write treats a CTRL+Z character in the buffer as an output terminator.

Example

/* WRITE.C: This program opens a file for output
 * and uses _write to write some bytes to the file.
 */

#include <io.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

char buffer[] = "This is a test of '_write' function";

void main( void )
{
   int fh;
   unsigned byteswritten;

   if( (fh = _open( "write.o", _O_RDWR | _O_CREAT,
                               _S_IREAD | _S_IWRITE )) != -1 )
   {
      if(( byteswritten = _write( fh, buffer, sizeof( buffer ))) == -1 )
         perror( "Write failed" );
      else
         printf( "Wrote %u bytes to file\n", byteswritten );

      _close( fh );
   }
}

Output

Wrote 36 bytes to file

Low-level I/O Routines

See Also fwrite, _open, _read


_wtoi, _wtoi64, _wtol

Converts a wide-character string to an integer (_wtoi and _wtoi64) or to a long integer (_wtol).

int _wtoi( const wchar_t *string );

__int64 _wtoi64( wchar_t *string );

long _wtol( const wchar_t *string );

Routine | Required Header | Compatibility
_wtoi | <stdlib.h> or <wchar.h> | Win 95, Win NT
_wtoi64 | <stdlib.h> or <wchar.h> | Win 95, Win NT
_wtol | <stdlib.h> or <wchar.h> | Win 95, Win NT

For additional compatibility information, see Compatibility in the Introduction.

Libraries

LIBC.LIB | Single thread static library, retail version
LIBCMT.LIB | Multithread static library, retail version
MSVCRT.LIB | Import library for MSVCRT.DLL, retail version

Return Value

Each function returns the int, __int64, or long value produced by interpreting the input characters as a number. If the input cannot be converted to a value of the appropriate type, _wtoi and _wtoi64 return 0 and _wtol returns 0L. The return value is undefined in case of overflow.

Parameter

string

String to be converted

Remarks

The _wtoi and _wtoi64 function converts a wide-character string to an integer value. _wtol converts a wide-character string to a long integer value. The input string is a sequence of characters that can be interpreted as a numerical value of the specified type. The output value is affected by the setting of the LC_NUMERIC category of the current locale. (For more information on the LC_NUMERIC category, see setlocale.The function stops reading the input string at the first character that it cannot recognize as part of a number. This character may be the null character (L'\0') terminating the string.

The string argument for these functions has the form

[whitespace] [sign]digits

A whitespace consists of space and/or tab characters, which are ignored. sign is either plus (+) or minus ( – ). digits is one or more decimal digits. _wtoi, _wtoi64, and _wtol do not recognize decimal points or exponents.

Example

/* ATOF.C: This program shows how numbers stored
 * as strings can be converted to numeric values
 * using the atof, atoi, and atol functions.
 */

#include <stdlib.h>
#include <stdio.h>

void main( void )
{
   char *s; double x; int i; long l;

   s = "  -2309.12E-15";    /* Test of atof */
   x = atof( s );
   printf( "atof test: ASCII string: %s\tfloat:  %e\n", s, x );

   s = "7.8912654773d210";  /* Test of atof */
   x = atof( s );
   printf( "atof test: ASCII string: %s\tfloat:  %e\n", s, x );

   s = "  -9885 pigs";      /* Test of atoi */
   i = atoi( s );
   printf( "atoi test: ASCII string: %s\t\tinteger: %d\n", s, i );

   s = "98854 dollars";     /* Test of atol */
   l = atol( s );
   printf( "atol test: ASCII string: %s\t\tlong: %ld\n", s, l );
}

Output

atof test: ASCII string:   -2309.12E-15   float:  -2.309120e-012
atof test: ASCII string: 7.8912654773d210   float:  7.891265e+210
atoi test: ASCII string:   -9885 pigs      integer: -9885
atol test: ASCII string: 98854 dollars      long: 98854

Data Conversion Routines | Locale Routines

See Also atoi, _ecvt, _fcvt, _gcvt


Language and Country/Region Strings

The locale argument to the setlocale function takes the following form:

locale  "lang[_country[.code_page]]"
            | ".code_page"
            | ""
            | NULL

This appendix lists the language strings and country/region strings available to setlocale. All country/region and language codes currently supported by the Win32 NLS API are supported by setlocale. For information on code pages, see Code Pages in Chapter 1.


Language Strings

The following language strings are recognized by setlocale. Any language not supported by the operating system is not accepted by setlocale. The three-letter language-string codes are only valid in Windows NT and Windows 95.

Primary Language | Sublanguage | Language String
Chinese | Chinese | "chinese"
Chinese | Chinese (simplified) | "chinese-simplified" or "chs"
Chinese | Chinese (traditional) | "chinese-traditional" or "cht"
Czech | Czech | "csy" or "czech"
Danish | Danish | "dan"or "danish"
Dutch | Dutch (Belgian) | "belgian", "dutch-belgian", or "nlb"
Dutch | Dutch (default) | "dutch" or "nld"
English | English (Australian) | "australian", "ena", or "english-aus"
English | English (Canadian) | "canadian", "enc", or "english-can"
English | English (default) | "english"
English | English (New Zealand) | "english-nz" or "enz"
English | English (UK) | "eng", "english-uk", or "uk"
English | English (USA) | "american", "american english", "american-english", "english-american", "english-us", "english-usa", "enu", "us", or "usa"
Finnish | Finnish | "fin" or "finnish"
French | French (Belgian) | "frb" or "french-belgian"
French | French (Canadian) | "frc" or "french-canadian"
French | French (default) | "fra"or "french"
French | French (Swiss) | "french-swiss" or "frs"
German | German (Austrian) | "dea" or "german-austrian"
German | German (default) | "deu" or "german"
German | German (Swiss) | "des", "german-swiss", or "swiss"
Greek | Greek | "ell" or "greek"
Hungarian | Hungarian | "hun" or "hungarian"
Icelandic | Icelandic | "icelandic" or "isl"
Italian | Italian (default) | "ita" or "italian"
Italian | Italian (Swiss) | "italian-swiss" or "its"
Japanese | Japanese | "japanese" or "jpn"
Korean | Korean | "kor" or "korean"
Norwegian | Norwegian (Bokmal) | "nor" or "norwegian-bokmal"
Norwegian | Norwegian (default) | "norwegian"
Norwegian | Norwegian (Nynorsk) | "non" or "norwegian-nynorsk"
Polish | Polish | "plk" or "polish"
Portuguese | Portuguese (Brazilian) | "portuguese-brazilian" or "ptb"
Portuguese | Portuguese (default) | "portuguese" or "ptg"
Russian | Russian (default) | "rus" or "russian"
Slovak | Slovak | "sky" or "slovak"
Spanish | Spanish (default) | "esp" or "spanish"
Spanish | Spanish (Mexican) | "esm" or "spanish-mexican"
Spanish | Spanish (Modern) | "esn" or "spanish-modern"
Swedish | Swedish | "sve" or "swedish"
Turkish | Turkish | "trk" or "turkish"


Country/Region Strings

The following is a list of country/regions strings recognized by setlocale. Strings for countries/regions that are not supported by the operating system are not accepted by setlocale. Three-letter country/region-name codes are from ISO/IEC (International Organization for Standardization, International Electrotechnical Commission) specification 3166.

Country/Region | Country/Region String
Australia | "aus" or "australia"
Austria | "austria" or "aut"
Belgium | "bel" or "belgium"
Brazil | "bra" or "brazil"
Canada | "can" or "canada"
Czech Republic | "cze" or "czech"
Denmark | "denmark" or "dnk"
Finland | "fin" or "finland"
France | "fra" or "france"
Germany | "deu" or "germany"
Greece | "grc" or "greece"
Hong Kong | "hkg", "hong kong", or "hong-kong"
Hungary | "hun" or "hungary"
Iceland | "iceland" or "isl"
Ireland | "ireland" or "irl"
Italy | "ita" or "italy"
Japan | "japan" or "jpn"
Mexico | "mex" or "mexico"
Netherlands | "nld", "holland", or "netherlands"
New Zealand | "new zealand", "new-zealand", "nz", or "nzl"
Norway | "nor" or "norway"
People’s Republic of China | "china", "chn", "pr china", or "pr-china"
Poland | "pol" or "poland"
Portugal | "prt" or "portugal"
Russia | "rus" or "russia"
Singapore | "sgp" or "singapore"
Slovak Repubic | "svk" or "slovak"
South Korea | "kor", "korea", "south korea", or "south-korea"
Spain | "esp" or "spain"
Sweden | "swe" or "sweden"
Switzerland | "che" or "switzerland"
Taiwan | "taiwan" or "twn"
Turkey | "tur" or "turkey"
United Kingdom | "britain", "england", "gbr", "great britain", "uk", "united kingdom", or "united-kingdom"
United States of America | "america", "united states", "united-states", "us", or "usa"


Generic-Text Mappings

To simplify writing code for international markets, generic-text mappings are defined in TCHAR.H for:

  • Data types

  • Constants and global variables

  • Routine mappings

For more information, see Using Generic-Text Mappings in Chapter 1. Generic-text mappings are Microsoft extensions that are not ANSI-compatible.

See Also Data type mappings, Constants and global variables, Routine mappings, A sample generic-text program, Using generic-text mappings


Data Type Mappings

These data-type mappings are defined in TCHAR.H and depend on whether the constant _UNICODE or _MBCS has been defined in your program.

For related information, see Using TCHAR.H Data Types with _MBCS Code.

Generic-Text Data Type Mappings

Generic-Text Data Type Name | SBCS (_UNICODE, _MBCS Not Defined) | _MBCS Defined | _UNICODE Defined
_TCHAR | char | char | wchar_t
_TINT | int | int | wint_t
_TSCHAR | signed char | signed char | wchar_t
_TUCHAR | unsigned char | unsigned char | wchar_t
_TXCHAR | char | unsigned char | wchar_t
_T or _TEXT | No effect (removed by preprocessor) | No effect (removed by preprocessor) | L (converts following character or string to its Unicode counterpart)

See Also Generic-text mappings, Constants and global variable mappings, Routine mappings, A sample generic-text program, Using generic-text mappings


Constant and Global Variable Mappings

These generic-text constant, global variable, and standard-type mappings are defined in TCHAR.H and depend on whether the constant _UNICODE or _MBCS has been defined in your program.

Generic-Text Constant and Global Variable Mappings

Generic-Text – Object Name | SBCS (_UNICODE, _MBCS Not Defined) | _MBCS Defined | _UNICODE Defined
_TEOF | EOF | EOF | WEOF
_tenviron | _environ | _environ | _wenviron
_tfinddata_t | _finddata_t | _finddata_t | _wfinddata_t

See Also Generic-text mappings, Data type mappings, Routine mappings, A sample generic-text program, Using generic-text mappings


Routine Mappings

The generic-text routine mappings are defined in TCHAR.H. _tccpy and _tclen map to functions in the MBCS model; they are mapped to macros or inline functions in the SBCS and Unicode models for completeness. For information on a generic text routine, see the help topic about the corresponding SBCS-, _MBCS-, or _UNICODE-related routine.

More specific information about individual routines listed in the left column below is not available in this documentation. However, you can easily look up the information on a corresponding SBCS-, _MBCS-, or _UNICODE-related routine. Use the Search command on the Help menu to look up any generic-text routine listed below.

For related information, see Generic-Text Mappings in TCHAR.H.

Generic-Text Routine Mappings

Generic-Text Routine Name | SBCS (_UNICODE & MBCS Not Defined) | _MBCS Defined | _UNICODE Defined
_fgettc | fgetc | fgetc | fgetwc
_fgettchar | fgetchar | fgetchar | _fgetwchar
_fgetts | fgets | fgets | fgetws
_fputtc | fputc | fputc | fputwc
_fputtchar | fputchar | fputchar | _fputwchar
_fputts | fputs | fputs | fputws
_ftprintf | fprintf | fprintf | fwprintf
_ftscanf | fscanf | fscanf | fwscanf
_gettc | getc | getc | getwc
_gettchar | getchar | getchar | getwchar
_getts | gets | gets | getws
_istalnum | isalnum | _ismbcalnum | iswalnum
_istalpha | isalpha | _ismbcalpha | iswalpha
_istascii | __isascii | __isascii | iswascii
_istcntrl | iscntrl | iscntrl | iswcntrl
_istdigit | isdigit | _ismbcdigit | iswdigit
_istgraph | isgraph | _ismbcgraph | iswgraph
_istlead | Always returns false | _ismbblead | Always returns false
_istleadbyte | Always returns false | isleadbyte | Always returns false
_istlegal | Always returns true | _ismbclegal | Always returns true
_istlower | islower | _ismbclower | iswlower
_istprint | isprint | _ismbcprint | iswprint
_istpunct | ispunct | _ismbcpunct | iswpunct
_istspace | isspace | _ismbcspace | iswspace
_istupper | isupper | _ismbcupper | iswupper
_istxdigit | isxdigit | isxdigit | iswxdigit
_itot | _itoa | _itoa | _itow
_ltot | _ltoa | _ltoa | _ltow
_puttc | putc | putc | putwc
_puttchar | putchar | putchar | putwchar
_putts | puts | puts | putws
_tmain | main | main | wmain
_sntprintf | _snprintf | _snprintf | _snwprintf
_stprintf | sprintf | sprintf | swprintf
_stscanf | sscanf | sscanf | swscanf
_taccess | _access | _access | _waccess
_tasctime | asctime | asctime | _wasctime
_tccpy | Maps to macro or inline function | _mbccpy | Maps to macro or inline function
_tchdir | _chdir | _chdir | _wchdir
_tclen | Maps to macro or inline function | _mbclen | Maps to macro or inline function
_tchmod | _chmod | _chmod | _wchmod
_tcreat | _creat | _creat | _wcreat
_tcscat | strcat | _mbscat | wcscat
_tcschr | strchr | _mbschr | wcschr
_tcsclen | strlen | _mbslen | wcslen
_tcscmp | strcmp | _mbscmp | wcscmp
_tcscoll | strcoll | _mbscoll | wcscoll
_tcscpy | strcpy | _mbscpy | wcscpy
_tcscspn | strcspn | _mbscspn | wcscspn
_tcsdec | _strdec | _mbsdec | _wcsdec
_tcsdup | _strdup | _mbsdup | _wcsdup
_tcsftime | strftime | strftime | wcsftime
_tcsicmp | _stricmp | _mbsicmp | _wcsicmp
_tcsicoll | _stricoll | _stricoll | _wcsicoll
_tcsinc | _strinc | _mbsinc | _wcsinc
_tcslen | strlen | strlen | wcslen
_tcslwr | _strlwr | _mbslwr | _wcslwr
_tcsnbcnt | _strncnt | _mbsnbcnt | _wcnscnt
_tcsncat | strncat | _mbsnbcat | wcsncat
_tcsnccat | strncat | _mbsncat | wcsncat
_tcsncmp | strncmp | _mbsnbcmp | wcsncmp
_tcsnccmp | strncmp | _mbsncmp | wcsncmp
_tcsnccnt | _strncnt | _mbsnccnt | _wcsncnt
_tcsnccpy | strncpy | _mbsncpy | wcsncpy
_tcsncicmp | _strnicmp | _mbsnicmp | _wcsnicmp
_tcsncpy | strncpy | _mbsnbcpy | wcsncpy
_tcsncset | _strnset | _mbsnset | _wcsnset
_tcsnextc | _strnextc | _mbsnextc | _wcsnextc
_tcsnicmp | _strnicmp | _mbsnicmp | _wcsnicmp
_tcsnicoll | _strnicoll | _strnicoll | _wcsnicoll
_tcsninc | _strninc | _mbsninc | _wcsninc
_tcsnccnt | _strncnt | _mbsnccnt | _wcsncnt
_tcsnset | _strnset | _mbsnbset | _wcsnset
_tcspbrk | strpbrk | _mbspbrk | wcspbrk
_tcsspnp | _strspnp | _mbsspnp | _wcsspnp
_tcsrchr | strrchr | _mbsrchr | wcsrchr
_tcsrev | _strrev | _mbsrev | _wcsrev
_tcsset | _strset | _mbsset | _wcsset
_tcsspn | strspn | _mbsspn | wcsspn
_tcsstr | strstr | _mbsstr | wcsstr
_tcstod | strtod | strtod | wcstod
_tcstok | strtok | _mbstok | wcstok
_tcstol | strtol | strtol | wcstol
_tcstoul | strtoul | strtoul | wcstoul
_tcsupr | _strupr | _mbsupr | _wcsupr
_tcsxfrm | strxfrm | strxfrm | wcsxfrm
_tctime | ctime | ctime | _wctime
_texecl | _execl | _execl | _wexecl
_texecle | _execle | _execle | _wexecle
_texeclp | _execlp | _execlp | _wexeclp
_texeclpe | _execlpe | _execlpe | _wexeclpe
_texecv | _execv | _execv | _wexecv
_texecve | _execve | _execve | _wexecve
_texecvp | _execvp | _execvp | _wexecvp
_texecvpe | _execvpe | _execvpe | _wexecvpe
_tfdopen | _fdopen | _fdopen | _wfdopen
_tfindfirst | _findfirst | _findfirst | _wfindfirst
_tfindnext | _findnext | _findnext | _wfindnext
_tfopen | fopen | fopen | _wfopen
_tfreopen | freopen | freopen | _wfreopen
_tfsopen | _fsopen | _fsopen | _wfsopen
_tfullpath | _fullpath | _fullpath | _wfullpath
_tgetcwd | _getcwd | _getcwd | _wgetcwd
_tgetenv | getenv | getenv | _wgetenv
_tmain | main | main | wmain
_tmakepath | _makepath | _makepath | _wmakepath
_tmkdir | _mkdir | _mkdir | _wmkdir
_tmktemp | _mktemp | _mktemp | _wmktemp
_tperror | perror | perror | _wperror
_topen | _open | _open | _wopen
_totlower | tolower | _mbctolower | towlower
_totupper | toupper | _mbctoupper | towupper
_tpopen | _popen | _popen | _wpopen
_tprintf | printf | printf | wprintf
_tremove | remove | remove | _wremove
_trename | rename | rename | _wrename
_trmdir | _rmdir | _rmdir | _wrmdir
_tsearchenv | _searchenv | _searchenv | _wsearchenv
_tscanf | scanf | scanf | wscanf
_tsetlocale | setlocale | setlocale | _wsetlocale
_tsopen | _sopen | _sopen | _wsopen
_tspawnl | _spawnl | _spawnl | _wspawnl
_tspawnle | _spawnle | _spawnle | _wspawnle
_tspawnlp | _spawnlp | _spawnlp | _wspawnlp
_tspawnlpe | _spawnlpe | _spawnlpe | _wspawnlpe
_tspawnv | _spawnv | _spawnv | _wspawnv
_tspawnve | _spawnve | _spawnve | _wspawnve
_tspawnvp | _spawnvp | _spawnvp | _tspawnvp
_tspawnvpe | _spawnvpe | _spawnvpe | _tspawnvpe
_tsplitpath | _splitpath | _splitpath | _wsplitpath
_tstat | _stat | _stat | _wstat
_tstrdate | _strdate | _strdate | _wstrdate
_tstrtime | _strtime | _strtime | _wstrtime
_tsystem | system | system | _wsystem
_ttempnam | _tempnam | _tempnam | _wtempnam
_ttmpnam | tmpnam | tmpnam | _wtmpnam
_ttoi | atoi | atoi | _wtoi
_ttol | atol | atol | _wtol
_tutime | _utime | _utime | _wutime
_tWinMain | WinMain | WinMain | wWinMain
_ultot | _ultoa | _ultoa | _ultow
_ungettc | ungetc | ungetc | ungetwc
_vftprintf | vfprintf | vfprintf | vfwprintf
_vsntprintf | _vsnprintf | _vsnprintf | _vsnwprintf
_vstprintf | vsprintf | vsprintf | vswprintf
_vtprintf | vprintf | vprintf | vwprintf

See Also Generic-text mappings, Data type mappings, Constants and global variable mappings, A sample generic-text program, Using generic-text mappings


Build Errors

This section is an alphanumeric reference of error messages generated by the build tools. To get help on a particular error message, either click the mouse pointer on an error number in the Output window and press F1, or click Search on the Help menu and type the error number in the Index tab find box.

Interesting home pages
Visual C++ Home The entire Visual C++ product.
Compiling and Linking Building your program.
Debugging Debugging your program.


BSCMAKE Errors BK1500 through BK4503

The following topics cover Error BK1500 through Warning BK4503.


BSCMAKE Error BK1500

UNKNOWN ERROR

BSCMAKE detected an unknown error condition.

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


BSCMAKE Error BK1501

unknown character 'character' in option 'option'

BSCMAKE did not recognize the given character specified for the given option.


BSCMAKE Error BK1502

incomplete specification for option 'option'

The given option did not contain the correct syntax.


BSCMAKE Error BK1503

cannot write to file 'filename' [: reason]

BSCMAKE could not write to the given file. This message may be followed by a reason from the operating system, giving additional information.

One of the following may have occurred:

  • The disk was full.

  • A hardware error occurred.


BSCMAKE Error BK1504

cannot position in file 'filename' [: reason]

BSCMAKE could not move to a location in the given file. This message may be followed by a reason from the operating system, giving additional information.

One of the following may have occurred:

  • The disk was full.

  • A hardware error occurred.

  • The file was truncated. Truncation can occur if the compiler runs out of disk space or is interrupted when it is creating the .SBR file.


BSCMAKE Error BK1505

cannot read from file 'filename' [: reason]

BSCMAKE could not read from the given file. This message may be followed by a reason from the operating system, giving additional information.

One of the following may have occurred:

  • The file was corrupt.

  • The file was truncated. Truncation can occur if the compiler runs out of disk space or is interrupted when it is creating the .SBR file.


BSCMAKE Error BK1506

cannot open file 'filename' [: reason]

BSCMAKE could not open the given file. This message may be followed by a message from the operating system, giving additional information.

One of the following may have occurred:

  • The file was locked by another process. If reason was Permission denied, the browser in the development environment might be using the file. Close the Browse window and repeat the build.

  • The disk was full.

  • A hardware error occurred.

  • The specified output file had the same name as an existing subdirectory.


BSCMAKE Error BK1507

cannot open temporary file 'filename' [: reason]

BSCMAKE could not open one of its temporary files. This message may be followed by a reason from the operating system, giving additional information.

One of the following may have occurred:

  • The TMP environment variable was not set to a valid drive and directory.

  • The disk was full.


BSCMAKE Error BK1508

cannot delete temporary file 'filename' [: reason]

BSCMAKE could not delete one of its temporary files. This message may be followed by a reason from the operating system, giving additional information.

One of the following may have occurred:

  • Another process had the file open.

  • A hardware error occurred.


BSCMAKE Error BK1509

out of heap space

BSCMAKE ran out of memory, including virtual memory.

One of the following may be a solution:

  • Increase the size of the swap file.

  • Free some space on disk.

  • Increase the size of the Windows swap file.

  • Reduce the memory that BSCMAKE will require by using one or more options. Use /Ei or /Es to eliminate some input files. Use /Em to eliminate macro bodies.


BSCMAKE Error BK1510

corrupt .SBR file 'filename'

The given .SBR file is corrupt or does not have the expected format.

Recompile to regenerate the .SBR file.


BSCMAKE Error BK1511

invalid response file specification

BSCMAKE did not understand the command-line specification for the response file. The specification was probably wrong or incomplete.

For example, the following specification causes this error:

bscmake @


BSCMAKE Error BK1512

filename: capacity exceeded

BSCMAKE could not build a browse information file because the number of definitions, references, modules, or other information exceeded the limit.

One of the following may be a solution:

  • Exclude some information using the /Em, /Es, or /Ei option.

  • Omit the /Iu option, if it was used.


BSCMAKE Error BK1513

nonincremental update requires all .SBR files

An attempt was made to build a new browse information (.BSC) file, but one or more of the specified .SBR files was truncated. This message is always preceded by warning BK4502, which gives the name of the .SBR file that caused the error.

BSCMAKE can process a truncated, or zero-length, .SBR file only when a .BSC file already exists and is being incrementally updated.

One of the following may be a cause:

  • The .BSC file was missing.

  • The wrong filename was specified.

  • The file was corrupted, and a full build was required.


BSCMAKE Error BK1514

all .SBR files truncated, none found in filename

None of the .SBR files specified for an update was a part of the original browse information (.BSC) file. This message is always preceded by warning BK4502, which gives the name of the .SBR file that caused the error.

One of the following may be a cause:

  • The wrong filename was specified.

  • The file was corrupted, and a full build was required.


BSCMAKE Error BK1515

'bscfile': incompatible version: cannot incrementally update

The given browse information (.BSC) file was not created with this version of BSCMAKE. A .BSC file can be incrementally built only by the same version of BSCMAKE as the one used to fully build that file.


BSCMAKE Error BK1516

'bscfile' corrupt; cannot incrementally update

The given browse information (.BSC) file was corrupted, possibly due to a system failure during the build. Delete the .BSC file, rebuild all .SBR files, then rebuild the .BSC file.


BSCMAKE Error BK1517

source file for 'filename' compiled with both /Yc and /Yu

The given .SBR file refers to itself. Probably the file was recompiled with the /Yu option after compiling with /Yc.

Reset the compiler options for the source file to /Yc, then rebuild all to generate new .SBR files for the project. Do not subsequently compile the same source file using /Yu.


BSCMAKE Warning BK4500

UNKNOWN WARNING

An unknown warning condition was detected by BSCMAKE.

Note the circumstances of the warning, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


BSCMAKE Warning BK4501

ignoring unknown option 'option'

BSCMAKE did not recognize the given option and ignored it.


BSCMAKE Warning BK4502

truncated .SBR file 'filename' not in filename

The given zero-length .SBR file, specified during an update, was not originally part of the browse information (.BSC) file.

If a zero-length file that is not part of the original build of the .BSC file is specified during a rebuild of that file, BSCMAKE issues this warning. One of the following may be a cause:

  • The wrong filename was specified.

  • The file was deleted. (Error BK1513 will result.)

  • The file was corrupted, requiring a full build.


BSCMAKE Warning BK4503

minor error in .SBR file 'filename' ignored

The given .SBR file contained an error that did not halt the build. However, the resulting .BSC file may not be correct.

Recompile to regenerate the .SBR file.


Compiler Fatal Errors C999 through C1999

The following topics cover errors C999 through C1999.


Fatal Error C999

UNKNOWN MESSAGE
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information

This error most likely occurs when your error files (files with a .ERR extension) are from a different version of the compiler. You should try reinstalling the product.


Fatal Error C1001

INTERNAL COMPILER ERROR
(compiler file 'file', line number)

This error is most often generated in one of two cases:

  • Failure to recover the compiler's internal state following detection of a syntax error in the program. The first pass of the compiler will occasionally fail when attempting to recover its state following the detection of a malformed program. Typically, the compiler will have printed an error message (or messages) and will later produce an internal compiler error. In most cases, fixing the errors reported in your code and recompiling will solve the problem.

  • Failure of the code generator to find a way to generate correct code for a construct. This is most often caused by the interaction of an expression and an optimization option. The optimization has generated a tree which the compiler does not know how to handle. Such a problem can often be fixed by removing one or more optimization options when compiling the particular function containing the line indicated in the error message.

If no error messages have been emitted prior to the internal compiler error, then the next step is to determine which pass of the compiler is emitting the internal compiler error. This can be determined by recompiling the application with the /Bd option included. The /Bd option will cause each pass to print its name and arguments when it is invoked. The last pass invoked before the error is emitted is the one responsible.

If the pass indicated is P1, then the likely problem is still error recovery, as in number one above, but it is happening before the compiler has had a chance to emit the error message for the error it has just discovered. In such a case, examine the line on which the internal compiler error is reported. This line may also contain an unreported syntax error. Fixing any errors you find on that line will solve the internal compiler error in most cases. If you cannot find any error on that line or on the line previous to the one reported, contact Microsoft Product Support Services for help.

If the pass indicated is P2, then the problem can usually be fixed by removing one or more optimization options (or using a different code generator). You can determine which option is at fault by removing them one at a time and recompiling until the message goes away. Generally the last one removed is the problem and all other optimizations can be used safely. The most common culprits are /Og, /Oi, and /Oa. Once the offending optimization is discovered, it need not be turned off for the entire compilation. The offending optimization can be disabled with the optimize pragma while compiling the function where the error occurred, but enabled for the rest of the module.

More rarely, such errors occur at very low optimization levels or even when optimization is disabled. In such cases, rewriting the line where the error is reported (or possibly several lines including the one causing the error) may be a solution. If none of these options works, consult the technical support help file or the technical support section in one of your manuals.


Fatal Error C1002

compiler is out of heap space in pass 2

The compiler ran out of dynamic memory space during execution of the second pass of the compiler (C2.EXE). Usually this means the program has too many symbols and/or complex expressions.

One of the following may be a solution:

  • Divide the file into several smaller source files.

  • Break expressions into smaller subexpressions.

  • Remove other programs or drivers running in the system that could be consuming significant amounts of memory.


Fatal Error C1003

error count exceeds number; stopping compilation

Errors in the program were too numerous to allow recovery, and the compiler must terminate.


Fatal Error C1004

unexpected end of file found

The compiler reached the end of a source file without resolving a construct.

For instance, a function or structure definition may be missing a closing curly brace, a class definition may be missing a semicolon after its closing brace, a function call or expression may have mismatched parentheses, and so on.

In addition to these common causes, one of the following reasons may have caused this error:

  • The default disk drive did not contain sufficient space for compiler-generated temporary files. The space required is approximately two times the size of the source file.

  • An #if directive evaluates to false without a corresponding closing #endif directive.

  • The precompiled headers option (/Yu) is enabled but the file doesn't contain a hdrstop pragma.

  • The /Yufilename option is used and the source file being compiled does not contain an #include "filename" directive that uses the same filename used with /Yu.

  • A source file does not end with a carriage return–linefeed pair.

Tips

  • Make sure that each opening brace has a matching closing brace.

  • Make sure that each opening parenthesis has a matching closing parenthesis.

  • Make sure all class definitions have a semicolon after the closing brace for the class.

  • When using C-style comments (i.e. /* ... */), make sure there is a closing asterisk-slash ( */ ) combination.


Fatal Error C1005

string too big for buffer

A string in a compiler intermediate file overflowed a buffer.


Fatal Error C1006

write error on compiler-generated file

The compiler was unable to create the intermediate files used in the compilation process.

This error can be caused by a disk media error or by an open floppy drive door.


Fatal Error C1007

unrecognized flag 'string' in 'option'

The string in the command-line option was not valid.

Tips

  • Check the CL command line and CL environment variable for errors in option specifications.


Fatal Error C1008

no input file specified

The compiler was not given a file to compile.

The compiler must be given a C or C++ source file to compile. Check the CL command line and CL environment variable for filename specifications.


Fatal Error C1009

compiler limit : macros nested too deeply

Too many macros were being expanded at the same time.

This error occurs when a macro definition contains macros to be expanded and those macros contain other macros. The compiler has a limit of 256 levels of nested macros.

Try to split the nested macros into simpler macros.


Fatal Error C1010

unexpected end of file while looking for precompiled header directive

A precompiled header was specified, but it did not contain a precompiled header directive.

This error can be caused by specifying an incorrect file as a header file, or by specifying an include file with the /Yu (Use Precompiled Header) command line option that is not listed in the source file as an include file.


Fatal Error C1011

compiler limit : 'identifier' : macro definition too big, exceeds: number bytes

The macro definition was longer than allowed.

Try to split the definition into shorter definitions.


Fatal Error C1012

unmatched parenthesis : missing 'character'

The parentheses in a preprocessor directive were not matched. The missing character is either a left or right parenthesis.


Fatal Error C1013

compiler limit : too many open parentheses

Too many levels of parentheses were used.

Simplify the expression, or calculate part of the expression in a separate statement.


Fatal Error C1014

too many include files : depth = level

The nesting depth of #include directives was too great.

Open files can be included by the use of nested directives. The source file containing the directive is counted as one of the files.


Fatal Error C1016

#if[n]def expected an identifier

The #ifdef or #ifndef conditional compilation directive was not supplied with an identifier to evaluate.

An identifier must be specified with the #ifdef and #ifndef directives.


Fatal Error C1017

invalid integer constant expression

The expression in an #if directive either did not exist or did not evaluate to a constant.

When using the #define statement to define a constant, its value must evaluate to an integer constant if it is to be used as the expression in an #if, #elif, or #else compiler directive. For example, this error occurs with the following code fragment:

#define CONSTANT_NAME "YES"
#if CONSTANT_NAME
...
#endif

Because CONSTANT_NAME evaluates to a string constant and not an integer constant, the #if directive generates this error and halts the compiler.

Another notable situation occurs when any constant that is undefined is evaluated by the preprocessor to be zero. If an undefined constant is used inadvertently, unintended behavior may result. For example, in the following code fragment, the result is the reverse of what is actually intended:

#define CONSTANT_NAME YES
#if CONSTANT_NAME
   // Code to use on YES...
#elif CONSTANT_NAME==NO
   // Code to use on NO...
#endif

In this example, YES is undefined, so it evaluates to zero. Therefore, CONSTANT_NAME is also zero. Thus, the #if expression CONSTANT_NAME evaluates to false and the code intended to be used on YES is removed by the preprocessor. Furthermore, because NO is also undefined, it also evaluates to zero, which means that the #elif expression CONSTANT_NAME==NO evaluates to true (0 == 0). This causes the preprocessor to leave the code in the #elif portion of the conditional statement, which is also not the intended behavior.

Tips

  • If you are not sure how the compiler is handling certain directives, you can compile the code with one of the preprocessor options (/P, /E, /EP). This will allow you to see the exact effect of the preprocessor directives on the code.


Fatal Error C1018

unexpected #elif

The #elif directive did not appear within an #if, #ifdef, or #ifndef construct.

Make sure that there is an #if, #ifdef, or #ifndef statement in effect before this statement.


Fatal Error C1019

unexpected #else

The #else directive did not appear within an #if, #ifdef, or #ifndef construct.

Make sure that there is an #if, #ifdef, or #ifndef statement in effect before this statement.


Fatal Error C1020

unexpected #endif

An #endif directive appeared without a matching #if, #ifdef, or #ifndef directive.

Make sure that there is a matching #endif for each #if, #ifdef, and #ifndef statement.


Fatal Error C1021

invalid preprocessor command 'string'

The characters following the number sign (#) did not form a valid preprocessor directive.

The number sign cannot be used as the first character in an identifier.


Fatal Error C1022

expected #endif

An #if, #ifdef, or #ifndef directive was not terminated with an #endif directive.

Make sure that there is an #if, #ifdef, or #ifndef statement in effect before this statement.


Fatal Error C1023

cannot open source file 'filename'

The given file either did not exist, could not be opened, or was not found.

If this error number appears without an error message, the compiler has run out of file handles.

Tips

  • Make sure that the environment settings are valid and that the correct path for the file is specified.

  • This error may be caused by not having enough file handles. Close some open applications and recompile.

  • Trying to open a file or directory for which you do not have permission can cause this error. Move the file to a directory where you do have access privileges, or ask your network administrator to grant you access to the file.

  • Make sure that the name of the file is spelled correctly.


Fatal Error C1024

cannot open include file 'filename'

The file specified in an #include preprocessor directive could not be found or could not be opened for other reasons. For instance, a network drive may be unavailable because of a network error that is not immediately apparent.

Tips

  • Make sure the filename is spelled correctly in the #include directive. Also, make sure the file extension (usually .H) is correct.

  • When compiling from the command prompt, make sure that the INCLUDE environment variable is valid and that the correct path for the file is specified. See The #include Directive in the Preprocessor Reference for more information.

  • When compiling in the Visual C++ environment, make sure the Include Files directories are set correctly by using the Directories tab on the Options dialog box (Tools menu).

  • If any include files are being accessed over a network, make sure that the networked machine is still available and that you have read permission for that machine. Often, rebooting a machine will reset the network interface card and the network will become available again.

  • The compiler may have run out of file handles. This is especially common when include files are deeply nested. To increase the number of file handles available to the compiler:
    • Close other files and applications.

    • Increase the number of file handles the operating system makes available to applications.

    • Reduce the level of nesting of include files.


Fatal Error C1026

parser stack overflow, program too complex

The program could not be processed because the space required to parse the program caused a stack overflow in the compiler.

Simplify the program by decreasing the complexity of expressions. Decrease the level of nesting in for and switch statements by putting some of the more deeply nested statements in separate functions. Break up very long expressions involving comma operators or function calls.


Fatal Error C1031

compiler limit : function calls nested too deeply

The program exceeded the dynamic compiler limit on nested function calls.

Split the nested calls, saving the return value from one of the nested functions in a temporary variable.


Fatal Error C1032

cannot open object code listing file 'filename'

The output listing file specified with the /Fl command-line option could not be opened.

There are several possible causes for this error:

  • The given name is not valid.

  • The file cannot be opened because of a lack of space.

  • A read-only file with the given name already exists.

  • The file is in use by another process.


Fatal Error C1033

cannot open program database 'filename'

There was an error opening the .PDB file. This may be caused by a disk error.


Fatal Error C1034

'file': no include path set

The INCLUDE environment variable was not set.

Set this variable using the Options command on the Tools menu. In the Options dialog box, select the Directiories tab. In the Show Directories For box, select Include Files. Then, in the Directories box, specify the path for the include files.

If you are using the command-line compiler, run the VCVARS32.BAT batch file to set the INCLUDE environment variable.


Fatal Error C1035

expression too complex; simplify expression

The compiler was unable to generate code for a complex expression.

Try to split the expression into simpler subexpressions and recompile.


Fatal Error C1036

cannot overwrite earlier program database format, delete 'filename' and recompile

This error is not used.


Fatal Error C1037

cannot open object file 'filename'

The object file specified with the /Fo command-line option could not be opened.

There are several possible causes for this error:

  • The given name is not valid.

  • The file cannot be opened because of a lack of space.

  • A read-only file with the given name already exists.

  • The file is in use by another process.


Fatal Error C1038

compiler limit : 'function' : control flow state too complex; simplify function

The number of possible control flow states in the specified function exceeded the limit imposed by the compiler. The flow control of the function should be simplified or the function should be split into smaller functions.


Fatal Error C1039

decl/defn not complete, cannot create precompiled header at this point

The last declaration or definition in the file was not complete, so a precompiled header file could not be created.


Fatal Error C1040

ILStore error for program database file: 'filename'

There was an error writing to the .PDB file. This may be caused by a lack of space on your disk, or a disk error.


Fatal Error C1041

cannot open compiler intermediate file - no more files

The compiler could not create intermediate files for use in the compilation process because no more file handles were available.


Fatal Error C1042

cannot open compiler intermediate file - no such file or directory

The compiler could not create intermediate files for use in the compilation process because the TMP environment variable was set to an invalid directory or path.

Use the SET command to change the TMP environment variable so that it points to a valid directory.


Fatal Error C1043

cannot open compiler intermediate file

The compiler could not create intermediate files for use in the compilation process. The exact reason could not be determined.

One of the following may be a solution:

  • Make sure that the environment variable TMP points to a drive and directory in which a file can be created.

  • Delete unneeded files in the TMP directory.


Fatal Error C1044

out of disk space for compiler intermediate file

The compiler could not create intermediate files for use in the compilation process because no more space was available.

Make more space available on the disk pointed to by the TMP environment variable and then recompile.


Fatal Error C1045

compiler limit : linkage specifications nested too deeply

The nesting of externals exceeded the capacity of the compiler. Nested externals are allowed when specifying the external linkage type (such as extern C++).

Make sure that nested externals have appropriate closing braces.


Fatal Error C1046

compiler limit : structure nested too deeply

The given structure, union, or class exceeded the nesting limit of the compiler.

Structures, unions, and classes cannot be nested to more than 15 levels.

Rewrite the definition so that fewer structures, unions, or classes are nested. The structure, union, or class can be split into two or more parts by defining one or more of the nested structures using typedef.


Fatal Error C1047

limit of option exceeded at 'string'

The given option was specified too many times. The given string is the argument to the option that caused the error.

Check the CL environment variable for additional occurrences of the given command-line option.


Fatal Error C1048

unknown option 'character' in 'option'

The given character was not a valid letter for the option.

For example, the following line:

#pragma optimize( "*", on )

causes the following error:

unknown option '*' in '#pragma optimize'


Fatal Error C1049

invalid numerical argument 'string'

The compiler expected a numerical argument but received the given string.

This error may be caused by giving a hexadecimal number without the necessary \x prefix or by a misformed floating-point number.


Fatal Error C1051

program database file, 'filename', has an obsolete format, delete it and recompile

The compiler cannot update the program database file, which has an older version number. Delete the file and recompile your program.


Fatal Error C1052

compiler limit : #if or #ifdef blocks nested too deeply

The program exceeded the maximum of 32 nesting levels for #if and #ifdef directives.

This error can be caused by include files that use these preprocessor directives.


Fatal Error C1053

'<identifier>' : function too large

The function was too large to be compiled. You can try compiling without optimizations, or else divide the function into two or more functions.

Note that a function which calls inline routines can grow very large.


Fatal Error C1054

compiler limit : initializers nested too deeply

The compiler limit on the nesting of initializers was exceeded. The limit depends on the combination of types being initialized and may range from 10 to 15 levels.

Simplify the data types being initialized to reduce the levels of nesting, or assign initial values in separate statements after the declaration.


Fatal Error C1055

compiler limit : out of keys

The file being compiled contained too many symbols. The compiler sets up a symbol table and uses hash keys to look up symbols in the table. This error indicates that the compiler has reached its limit for these keys.

Tips

  • Try to split the file into smaller files, and recompile.

  • Only include header files that are absolutely necessary.

  • Where possible, reuse temporary and global variables so that fewer symbols are generated, and thus, fewer keys are needed.


Fatal Error C1056

compiler limit : out of macro expansion space: number bytes, when expanding token: 'token'

The compiler overflowed an internal buffer during the expansion of a macro.

Try to split the macros into simpler macros or remove nonessential space and tab characters from macro definitions that were used in the expansion.


Fatal Error C1057

unexpected end of file in macro expansion

The compiler has encountered the end of the source file while gathering the arguments of a macro invocation. Usually this is the result of a missing right parenthesis in the macro invocation.


Fatal Error C1058

compiler limit : too many formal arguments

The function declaration had too many formal arguments.

Reduce the number of arguments by passing structures or pointers to structures.


Fatal Error C1059

compiler is out of near heap space

The compiler ran out of storage for items that it stores in its near (default data segment) heap.

One of the following may be a solution:

  • Eliminate unnecessary include files, especially unneeded function prototypes.

  • Split the function at the given line number into two or more functions.

  • Split the current file into two or more files and compile them separately.


Fatal Error C1060

compiler is out of heap space

The operating system or the run-time library was unable to fill a request for more memory.

Tips

  • Increase the Windows swap-file space. For more information about increasing the swap-file space, refer to Help (in Windows 95) or Control Panel Help (in Windows NT).

  • Close other programs running in the system; these could be consuming significant amounts of memory.

  • Simplify the program:
    • Eliminate unnecessary include files, especially unneeded #defines and function prototypes.

    • Eliminate some global variables. For instance, use a pointer to allocate memory dynamically, at run time, instead of declaring a large array.

    • Eliminate unused declarations.

    • Split the current file into two or more files and compile them separately.


Fatal Error C1061

compiler limit : blocks nested too deeply

The code includes blocks that are nested to a level greater than the compiler limit (128 levels of nesting). Simplify block nesting in the code.


Fatal Error C1062

error while writing to preprocessor output file

The compilation command included the /P option to produce a preprocessor output file, but not enough disk space was available to hold the file.

Free more space on the destination drive or choose an alternate output drive.


Fatal Error C1063

compiler limit : compiler stack overflow

The program was too complex and caused the compiler stack to overflow. This error may be a result of recursive includes.

Tips

  • Simplify the program by splitting it into smaller source files, and recompile.


Fatal Error C1064

compiler limit : token overflowed internal buffer

The compiler read an identifier that was longer than the internal buffer used for identifier names.

Shorten the name and recompile.


Fatal Error C1065

compiler limit : out of tags

The file being compiled contained too many symbols.

Try to split the file into smaller files and compile them separately.


Fatal Error C1067

compiler limit : debug information module size exceeded

This error can be caused by a symbol with a decorated name that exceeds 247 characters.

Shorten the name of the symbol.


Fatal Error C1068

cannot open file 'filename'

The given file either did not exist, could not be opened, or was not found.

Make sure that the environment settings are valid and that the correct path for the file is specified.

If this error appears without an error message, the compiler has run out of file handles.


Fatal Error C1069

write error on file 'filename'

An error occurred while the compiler was trying to write to the file. One possible cause of this error is insufficient disk space.


Fatal Error C1070

mismatched #if/#endif pair in file 'filename'

The preprocessor found the #if, #ifdef, or #ifndef directive but did not find a corresponding #endif directive in the same source file.


Fatal Error C1071

unexpected end of file found in comment

The compiler found the end of a file while scanning a comment.

Probably a comment was not terminated. Begin at the end of the file and search backward for the beginning of a comment. A comment begins with /* and ends with */ as in:

/* This is a
comment */

A comment cannot be split across source files.

This error can also be caused by a comment on the last line of a source file that is not followed by a newline character as in:

int i; // error: last line not terminated by newline

To eliminate this error, go to the end of the line and enter a newline.


Fatal Error C1072

'filename' : cannot read file

The compiler encountered an error when trying to read a file.

This error can be caused by a disk error or by a file-sharing conflict.


Fatal Error C1073

Internal error involving incremental compilation (compiler file 'filename', line number)

There was an unspecified error during incremental compilation.

Compile the file without using incremental compilation. (From the Build menu, choose Settings. On the C/C++ tab of the Project Settings dialog box, select the Customize category and clear the Enable Incremental Compilation check box. From the command line, specify /Gi–.)


Fatal Error C1074

'IDB' is illegal extension for PDB file: filename

The compiler found the .IDB extension when it was expecting the .PDB extension.


Fatal Error C1075

end of file found before the left token at 'filename(linenumber)' was matched

The compiler expected to find a matching token before it reached the end of your source file but was unable to. Check whether your open brackets (and other paired characters such as curly braces) match with close brackets.


Fatal Error C1076

compiler limit : internal heap limit reached; use /Zm to specify a higher limit

The compiler ran out of storage for items that it stores in its heap. Usually this is the result of having too many symbols.

One of the following may be a solution:

  • Use the /Zm compiler option to set the compiler's memory allocation limit.

  • Simplify the program:
    • Eliminate unnecessary include files, especially unneeded #defines and function prototypes.

    • Eliminate some global variables. For instance, use a pointer to allocate memory dynamically, at run time, instead of declaring a large array.

    • Eliminate unused declarations.

    • Break up very large functions into smaller ones.

    • Break up very large classes into smaller ones.

    • Split the current file into two or more files and compile them separately.

Note If you get this error message immediately upon starting the build process, you have probably specified too high a value for /Zm, given the specific details of your program. Change the /Zm value to a lower one and re-run the build.


Fatal Error C1077

compiler limit : cannot have more than number command line options

You exceeded an internal limit the compiler places on command-line options. If you use the /D option to define symbols, you might want to place these definitions inside a header file to remove them from the command line. You also might want to check whether there are duplicate options on the command line or whether some options override other options (such as using both /Gi and /Gi–).


Fatal Error C1079

compiler limit : PCH file size limit exceeded

The PCH file size limit of 4 GB is exceeded. As the available memory space is 1 GB for Windows 95 and 2 GB for Windows NT, this error cannot occur.


Fatal Error C1080

compiler limit : command line option exceeded limit of number characters

This error is generated when a single argument passed to the compiler exceeds 256 characters.


Fatal Error C1081

'symbol': file name exceeds number bytes in length

This error occurs when the length of the full pathname of a file exceeds the number of characters specified by _MAX_PATH (260 characters). _MAX_PATH is defined in STDLIB.H.

This error may occur even if you call CL.EXE with a short file name, because the compiler sometimes needs to generate the full pathname of the file. For example:

cl -c myfile.cpp

may cause the compiler to generate the full pathname:

D:\<very-long-directory-path>\myfile.cpp


Fatal Error C1082

Cannot close filetype file: 'file': message

If the message "bad file number" is given, this error may have been caused by closing a file in the foreground while it is being used by a background compilation.


Fatal Error C1083

Cannot open filetype file: 'file': message

An error occurred opening the specified file.

Tips

  • This error can occur if the file, subdirectory, or disk on which it resides is read-only. In this case, make the file writable or move the file to a writable disk. See your operating system documentation for information on removing the read-only attribute from a file.

  • This error may be caused by not having enough file handles. Close some open applications and recompile.

  • Trying to open a file or directory for which you do not have permission can cause this error. Move the file to a directory where you do have access privileges, or ask your network administrator to grant you access to the file.

  • If an include file could not be opened, check that the INCLUDE environment variable is set correctly and that the name of the file is spelled correctly.

  • Using double quotation marks around a complete path specification in a #include directive causes the standard directories to NOT be searched. See The #include Directive in the Preprocessor Reference for more information.


Fatal Error C1084

Cannot read filetype file: 'file': message

If the message "bad file number" is given, this error may have been caused by saving a file in the foreground while it is being used by a background compilation.


Fatal Error C1085

Cannot write filetype file: 'file': message

If the message "bad file number" is given, this error may have been caused by saving a file in the foreground while it is being used by a background compilation.

This error can be caused by attempting to write to a read-only drive, a drive that is full, or by a sharing violation.


Fatal Error C1086

Cannot seek filetype file: 'file': message

The compiler was unable to complete an I/O operation.


Fatal Error C1087

Cannot tell filetype file: 'file': message

The compiler was unable to complete an I/O operation.


Fatal Error C1088

Cannot flush filetype file: 'file': message

The compiler was unable to complete an I/O operation.


Fatal Error C1089

Cannot truncate filetype file: ‘file’: message

This error message indicates a failed attempt to shrink a file to 0 length.


Fatal Error C1090

data allocation exceeds 64K

The specified segment has grown beyond 32 kilobytes, the maximum for data segments. You will need to reduce the size of the segment.

Note that inline functions in your source may greatly increase code size.


Fatal Error C1092

New data types and function prototypes are not supported by Edit and Continue; build required

You added or changed a data type or function prototype, making the type new to your source code since the last successful build. Edit and Continue only supports data types that were present in your source code during the latest build. Edit and Continue only supports a new or changed function prototype if the same prototype is used by another function that was present in your source code during the latest build.

To remove this error without ending the current debug session, restore the source code to its state before it produced this error. Then select the Apply Code Changes command on the Debug menu.

To remove this error without changing your source code, stop the current debug session by selecting Stop Debugging from the Debug menu. Select Build from the Build menu. After a successful build, you may debug the current source code.

For further information, see the Limitations of Edit and Continue.


Fatal Error C1093

bad 'flag' flag, would overwrite 'string1' with 'string2'

You should use flag only once on the command line since any other usage will overwrite a previous usage.


Fatal Error C1094

too many 'flag' flags, 'string'

You used flag too many times. The last usage was with the parameter string.


Fatal Error C1100

unable to initialize OLE : system error message

The compiler is unable to initialize the Component Object Model (COM) library. See CoInitialize in the Win32 documentation for more information.


Fatal Error C1126

'identifier' : automatic allocation exceeds size

The space allocated for the local variables of a function exceeded the given limit.

Use the malloc run-time function or the new function to allocate large amounts of space for data.

The total space required may be slightly larger than the space required for the local variables. For example, the compiler will add an extra 20 bytes to the stack allocation when a swapable function is compiled.


Fatal Error C1189

#error : user supplied error message

This error message is generated when there is an #error directive in the program. For example:

#undef _WIN32

#if !defined(_WIN32)
#error _WIN32 must be defined //error
#endif

int main() {
   return 0;
}


Fatal Error C1200

unexpected internal error handling template inline functions

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Fatal Error C1201

unable to continue after syntax error in template class definition

An unexpected error occurred while parsing a template class definition.

Fix any other errors and recompile. If that fails, note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Fatal Error C1202

recursive type or function dependency context too complex

A template definition was recursive, or its complexity exceeded compiler limits.

The following is an example of this error:

template<int n> class Factorial : public Factorial<n-1>
{
public:
    operator int ()
    {
        return Factorial <n-1>::operator int () * n;
    }
};

Factorial<7> facSeven; // error on this line


Fatal Error C1203

'keyword' : disabled in this compiler

You used a feature that is not supported in this version of the compiler (the Windows NT SDK compiler).


Fatal Error C1300

error accessing program database filename

This error is not used.


Fatal Error C1301

error accessing program database filename, invalid format, please delete and rebuild

This error is not used.


Fatal Error C1500

'filename' : cannot open inline function definition file

The given file either did not exist, could not be opened, or was not found.

Make sure that the environment settings are valid and that the correct path for the file is specified.

If this error appears without an error message, the compiler has run out of file handles.


Fatal Error C1501

compiler limit : too many temporary variables

The source file contained more than 17,500 temporary variables.

Split the file into smaller parts.


Fatal Error C1502

inline member-function definition missing '}'

The compiler reached the end of the file and did not find a matching closing brace.

Make sure that curly braces are matched.


Fatal Error C1503

default parameter definition missing ',' or ')'

After one or more default parameters were defined, neither a comma to indicate continuation nor a closing parenthesis to indicate termination of the function declaration was found.

Make sure that there are matching parentheses around the set of formal parameters.


Fatal Error C1504

type still ambiguous after parsing number tokens, unable to recover

The compiler could not resolve the type after looking ahead in the code.

Simplify the code to make the statement clearer. This error can often be eliminated by using an explicit type cast to an ambiguous expression.


Fatal Error C1505

unrecoverable parser look-ahead error

The compiler could not evaluate the code.

Simplify the code by making smaller classes or functions.


Fatal Error C1506

unrecoverable block scoping error

The block was too large to compile.

This error can be caused by mismatched curly braces or by an extremely large function or class.


Fatal Error C1507

previous user errors and subsequent error recovery halt further compilation

There were too many errors to continue compiling.

Correct some of the errors and compile again.


Fatal Error C1508

compiler limit : 'function' : more than 65535 argument bytes

The size of formal parameters passed to the specified function exceeded the limit of 65535 bytes.


Fatal Error C1509

compiler limit : too many exception handler states in function 'function'. simplify function

The compiler exceeded an internal limit for exception handler states (1,920 exception handler states). This error usually occurs because function contained an complex expression made of user-defined class variables and arithmetic operators.

Possible solutions:

  • Simplify expressions within function by grouping common subexpressions and assigning them to temporary variables.

  • Break the function into two or more functions containing fewer lines.


Fatal Error C1700

compiler compiler is out of far heap space

The compiler ran out of storage for items that it stores in its far heap. Usually this is the result of having too many symbols.

One of the following may be a solution:

  • Eliminate some global variables.

  • Split the current file into two or more files and compile them separately.

  • Remove other programs or drivers running in the system, which could be consuming significant amounts of memory.

  • Check your CONFIG.SYS and AUTOEXEC.BAT files for device drivers that are not currently needed. For example, you may need to remove SMARTDRV.EXE or reconfigure it to use less memory.


Fatal Error C1852

'filename' is not a valid precompiled header file

The given filename is not a precompiled header file.

Make sure that all /Yu command-line option and #pragma hdrstop statements specify valid precompiled header files. The compiler assumes the .PCH extension if none is provided.

This error is caused by giving the filename of a file that is not a precompiled header, such as an .HPP file.


Fatal Error C1853

'filename' is not a precompiled header file created with this compiler

The given precompiled header is not compatible with this version of the compiler.

Recompile the program or the header with the same version of the compiler.

This error can be caused by using a precompiled C++ file with C code.


Fatal Error C1854

cannot overwrite information formed during creation of the precompiled header in object file: 'filename'

You attempted to specify the /Yu option (use precompiled header) for a file after having specified the /Yc option (create precompiled header) for that same file previously.

If the file contains certain types of declarations (such as declarations that include the __declspec dllexport modifier), this particular usage of precompiled headers is illegal. You must restructure your .MAK file to avoid specifying /Yu on a file that was previously compiled /Yc.


Fatal Error C1900

Il mismatch between 'tool1' version 'number1' and 'tool2' version 'number2'

The intermediate language used in tool1 and tool2 did not match. Check that the most current version of each tool has been installed.


Fatal Error C1902

program database manager mismatch; please check your installation

A program database file (.PDB) was created with a more recent version of DBI.DLL than the one found during compilation. Check that the current version is installed on your system.


Fatal Error C1903

unable to recover from previous error(s); stopping compilation

The compiler found too many errors to continue compiling your code. You should correct the errors and recompile.


Fatal Error C1999

UNKNOWN FATAL ERROR
Please choose the Technical Support command on the Visual C++
Help menu, or open the Technical Support help file for more information

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Compiler Errors C2001 through C2099

The following topics cover compiler errors C2001 through C2099.


Compiler Error C2001

newline in constant

A string constant was continued on a second line without either a backslash (\) or closing and opening double quotation marks (").

To break a string constant that is on two lines in the source file, do one of the following:

  • End the first line with the line-continuation character, a backslash.

  • Close the string on the first line with a double quotation mark and open the string on the next line with another double quotation mark.

It is not sufficient to end the first line with \n, the escape sequence for embedding a newline character in a string constant.

The following are examples of incorrect and correct usage:

printf("Hello,             // error
    world");
printf("Hello,\n          //  error
    world");
printf("Hello,\           //  OK
 world");
printf("Hello,"            // OK
    " world");

Note that any spaces at the beginning of the next line after a line-continuation character are included in the string constant and that neither solution actually places a newline character into the string constant. The following examples embed this character:

printf("Hello,\n\
world");
printf("Hello,\
\nworld");
printf("Hello,\n"
    "world");
printf("Hello,"
 "\nworld");


Compiler Error C2002

invalid wide-character constant

The use of the multibyte-character constant was not legal.

This error can be caused if a wide character contains more bytes than expected.

Wide characters cannot be concatenated with ordinary string literals and cannot be used if the standard header, STDDEF.H, is not included.

Wide-character strings and constants must be preceded by the character 'L'.

The following example shows a wide-character constant:

L'mbconst'

Wide characters are supported in C.


Compiler Error C2003

expected 'defined id'

An identifier was expected after the specified preprocessing keyword.


Compiler Error C2004

expected 'defined(id)'

An identifier was expected after the left parenthesis following the specified preprocessing keyword.


Compiler Error C2005

#line expected a line number, found 'token'

A #line directive lacked the required line-number specification.


Compiler Error C2006

#include expected a filename, found 'token'

An #include directive lacked the required filename specification.


Compiler Error C2007

#define syntax

An identifier was expected following #define in a preprocessing directive.


Compiler Error C2008

'character' : unexpected in macro definition

The given character was found immediately following the name of the macro.


Compiler Error C2009

reuse of macro formal 'identifier'

The given identifier was used more than once in the formal parameter list of a macro definition.


Compiler Error C2010

'character' : unexpected in macro formal parameter list

The given character was used incorrectly in the formal parameter list of a macro definition.


Compiler Error C2011

'identifier' : 'type' type redefinition

The specified identifier was already defined as type type.

The following is an example of this error:

struct S;
union S;    // error


Compiler Error C2012

missing name following '<'

An #include directive lacked the required filename specification.


Compiler Error C2013

missing '>'

The closing angle bracket (>) was missing from an #include directive.


Compiler Error C2014

preprocessor command must start as first nonwhite space

Nonwhite space characters appeared before the number sign (#) of a preprocessor directive on the same line.


Compiler Error C2015

too many characters in constant

A character constant contained more than two characters.

Character constants are limited to one character (standard character constants) or two characters (long character constants).

Note that an escape sequence (for example, \t for tab) is converted to a single character.


Compiler Error C2016

no closing single quotation mark

A newline character was found before the closing single quotation mark of a character constant.


Compiler Error C2017

illegal escape sequence

An escape sequence appeared where one was not expected.

An escape sequence — a backslash ( \ ) followed by a number or letter — may occur only in a character or string constant.


Compiler Error C2018

unknown character 'hexnumber'

The ASCII character corresponding to the given hexadecimal number appeared in the source file but is an illegal character.

One possible cause of this error is corruption of the source file.


Compiler Error C2019

expected preprocessor directive, found 'character'

The given character followed a number sign (#), but it was not the first letter of a preprocessor directive.


Compiler Error C2020

'member' : 'class' member redefinition

The specified member of the specified base class or structure was redefined.

A function inherited from a base class or structure cannot be redefined.

If the function is redefined in the derived class, it should be declared as virtual in the base class.


Compiler Error C2021

expected exponent value, not 'character'

The given character was used as the exponent of a floating-point constant but was not a valid number.


Compiler Error C2022

'number' : too big for character

The octal number following a backslash (\) in a character or string constant was too large to be represented as a character.


Compiler Error C2023

divide by 0

The expression resulted in a division by zero.


Compiler Error C2024

mod by 0

The expression resulted in a modulo 0 operation.


Compiler Error C2025

'identifier' : enum/struct/union type redefinition

The given identifier had already been used for an enumeration, structure, or union tag.


Compiler Error C2026

string too big, trailing characters truncated

The string was longer than the limit of 2048 characters.

After adjacent strings are concatenated, a string cannot be longer than 2048 characters.


Compiler Error C2027

use of undefined type 'identifier'

The specified type was not defined.

A type cannot be used until it is defined.


Compiler Error C2028

struct/union member must be inside a struct/union

Structure or union member must be declared within the structure or union, respectively.


Compiler Error C2030

'identifier' : struct/union member redefinition

The identifier was used for more than one member of the same structure or union.


Compiler Error C2032

'identifier' : function cannot be member of struct/union 'identifier'

The specified structure or union was declared with a member function.

Member functions are allowed in C++ but not in C.


Compiler Error C2033

'identifier' : bit field cannot have indirection

The given bit field was declared as a pointer (*), which is not allowed.

The following is an example of this error:

struct S
{
   int *b : 1;  // error
};


Compiler Error C2034

'identifier' : type of bit field too small for number of bits

The number of bits specified in the bit-field declaration exceeded the number of bits in the given base type.


Compiler Error C2036

'class-key' : unknown size

The address of the specified undeclared identifier was used.

The size of an undeclared object cannot be used.

The following is an example of this error:

struct A* pA;
struct B { int i; };
B* pB;
void main()
{
   pA++;   // error, size of A not known
   pB++;   // OK, B has been declared
}


Compiler Error C2037

left of 'operator' specifies undefined struct/union 'identifier'

The expression before the member-selection operator ( -> or .) identified a structure or union type that was not defined.


Compiler Error C2039

'identifier' : is not a member of 'identifier'

A nonmember of a structure or union was incorrectly used.

The following is an example of this error:

struct S
{
   int mem0;
} *pS;
void main()
{
   pS->mem1 = 0;       // error, mem1 is not a member
   pS->mem0 = 0;       // OK
}


Compiler Error C2040

'operator' : 'identifier1' differs in levels of indirection from 'identifier2'

An expression involving the specified operator had inconsistent levels of indirection.

If both operands are of arithmetic type or if both are not (such as array or pointer), then they are used without change. If one operand is arithmetic, but the other is not, the arithmetic operator is converted to the type of the other operator.


Compiler Error C2041

illegal digit 'character' for base 'number'

The specified character was not a legal digit for the base that was used.

The following is an example of this error:

int i = 081; // error, 8 is not a legal digit
int i = 071; // OK


Compiler Error C2042

signed/unsigned keywords mutually exclusive

The keywords signed and unsigned were both used in a single declaration.

The following is an example of this error:

unsigned signed int i;      // error


Compiler Error C2043

illegal break

A break statement is legal only within a do, for, while, or switch statement.


Compiler Error C2044

illegal continue

A continue statement is legal only within a do, for, or while statement.


Compiler Error C2045

'identifier' : label redefined

The label appeared before more than one statement in the same function.


Compiler Error C2046

illegal case

The keyword case can appear only within a switch statement.


Compiler Error C2047

illegal default

The keyword default can appear only within a switch statement.


Compiler Error C2048

more than one default

A switch statement contained more than one default label.


Compiler Error C2049

case value 'value' already used

The case value was already used in this switch statement.

This error can be caused by enumerations or macros that evaluate to the same value.


Compiler Error C2050

switch expression not integral

A switch expression did not evaluate to an integral value.


Compiler Error C2051

case expression not constant

Case expressions must be integral constants.


Compiler Error C2052

case expression not integral

Case expressions must be integral constants.


Compiler Error C2053

'identifier' : wide string mismatch

The specified wide string was assigned to an incompatible type.

The following is an example of this error:

char array[] = L"Rika";    // error


Compiler Error C2054

expected '(' to follow 'identifier'

The context requires parentheses after the function identifier.

One cause of this error is omitting an equal sign (=) on a complex initialization, as in:

int array1[] { 1, 2, 3 };   // error, missing =
int array2[] = { 1, 2, 3 }; // OK


Compiler Error C2055

expected formal parameter list, not a type list

A parameter type list instead of a formal parameter list appeared in a function definition.

In ANSI C, the formal parameters in a function definition must all be named unless they are void or an ellipsis (...).


Compiler Error C2056

illegal expression

An expression was illegal because of a previous error that may not have produced an error message.


Compiler Error C2057

expected constant expression

The context requires a constant expression.


Compiler Error C2058

constant expression is not integral

The context requires an integral constant expression.


Compiler Error C2059

syntax error : 'token'

The token caused a syntax error. Problems of this type can sometimes be attributed to a syntactical or clerical error. For example:

void main (             // No closing parenthesis.
{

}

In the preceding example, the error message will be generated for the line which contains the open curly bracket, although the true source of the error appears on the line just above. As a general rule, make sure to also examine the lines above the line listed in the error message when trying to determine the cause.

Tips

  • If examining the line listed in the error message yields no clue to what the problem might be, try commenting out the line and recompiling the source code. Also, sometimes commenting out several lines directly above the line listed in the error message will help narrow down the cause.

  • If the error message occurs on a symbol immediately following a typedef'd variable, ensure that the variable has been defined somewhere in the source code.


Compiler Error C2060

syntax error : end of file found

At least one more token was expected.

Causes of this error include omitting a semicolon (;), as in:

int *p    // error

or omitting a closing brace (}) from the last function, as in:

main()
{         // error


Compiler Error C2061

syntax error : identifier 'identifier'

The compiler found identifier where it was not expected. This error can be caused by enclosing an initializer in parentheses. The error can be avoided by enclosing the declarator in parentheses or making it a typedef. The following example causes this error and shows two fixes:

class X {};
class Y {};
class Z {};
class W : public  X, public Y, public Z {};

void func ( W* pW )
{
    X* pX ( pW );     // Error: unexpected identifier 'pW'

    Y ( *pY ) ( pW ); // OK, declarator in parentheses

    typedef Z *pZ_t;
    pZ_t pZ ( pW );   // OK, typedef used for Z
}


Compiler Error C2062

type 'type' unexpected

The compiler did not expect the given type to appear here, possibly because it already had a required type.

This error can also be caused by a missing semicolon.


Compiler Error C2063

'identifier' : not a function

The given identifier was not declared as a function but was used as a function.

The following example in C generates this error:

int i, j;
j = i();    // error, i is not a function


Compiler Error C2064

term does not evaluate to a function

A call was made to a function through an expression that did not evaluate to a function pointer.

This error is probably caused by attempting to call a nonfunction.

The following is an example of this error:

int i, j;
char* p;
void func()
{
   j = i();    // error, i is not a function
   p();        // error, p doesn't point to a function
}


Compiler Error C2065

'identifier' : undeclared identifier

The specified identifier was not declared.

A variable’s type must be specified in a declaration before it can be used. The parameters that a function uses must be specified in a declaration, or prototype, before the function can be used.

Tips

  • Make sure any include file containing the required declaration is not omitted.

  • Make sure you are including any necessary header files if you have defined VC_EXTRALEAN, WIN32_LEAN_AND_MEAN, or WIN32_EXTRA_LEAN. Defining these symbols excludes some functionality (certain header files are excluded) from windows.h and afxv_w32.h (for MFC applications) to speed compiles. Search windows.h and afxv_w32.h for these symbols for the most up-to-date description of what is excluded.

  • Make sure the identifier name is spelled correctly.

  • Make sure the identifier is using the correct upper- and lowercase letters.

  • Make sure all string constants have closing quotes.

  • This error can be caused by having a newline character in a string constant without a continuation character. For example:
    #include <stdio.h>
main() {
printf("\n %s
%s    // error: 's' : undeclared identifier
%s",
"this", "is", "it");
}
  • Special considerations must be taken when splitting a constant string over several lines. The most common method is to change the format string. Strings separated only by whitespace (spaces, tabs, newlines) are concatenated. For example:
    #include <stdio.h>
main() {
printf("\n %s"
 " %s"
 " %s",
 "this", "is", "it");
 }
  • An older, less-preferred method is to use line continuation by typing a backslash at the end of a line. For example:
    printf("\n %s\
 %s\
 %s",
 "this", "is", "it");

    This method is not often used because the spaces at the beginning of each continued line become part of the string.

  • Make sure you're using proper namespace scope. For example, in order to properly resolve ANSI C++ Standard Library functions and operators, you must state that you're using the std namespace with the using directive.

    For example, unless the using directive is uncommented, the following sample will fail to compile because the cout stream is defined in the std namespace:

    #include <iostream>
// using namespace std;
void main()
{
     cout << "Hello" << endl;
}


Compiler Error C2066

cast to function type is illegal

An object was cast to a function type, which is illegal.

In ANSI C, it is not legal to cast between a pointer to a function and a pointer to data.


Compiler Error C2067

cast to array type is illegal

An object was cast to an array type.


Compiler Error C2068

illegal cast from 'type1' to 'type2'

A type used in a cast operation was not legal for this expression.


Compiler Error C2069

cast of 'void' term to non-'void'

A term of type void was cast to a different type.

Type void cannot be cast to any other type.


Compiler Error C2070

illegal sizeof operand

The operand of a sizeof expression was not an expression or a type name.


Compiler Error C2071

'identifier' : illegal storage class

The named identifier was declared with an illegal storage class.


Compiler Error C2072

'identifier' : initialization of a function

An initializer for a function was illegally specified.


Compiler Error C2073

'identifier' : partially initialized array requires a default constructor

An array of user-defined types or an array of consists was specified with too few initializers.

If an explicit initializer (and its corresponding constructor) is not specified for a member of an array, then a default constructor must be supplied.

The following is an example of this error:

class A
{
public:
   A( int );              // constructor for ints only
};
A a[3] = { A(1), A(2) };  // error, no default constructor
class B
{
public:
   B();                   // default constructor declared
   B( int );
};
B b[3] = { B(1), B(2) };  // OK


Compiler Error C2074

'identifier' : 'class-key' initialization needs curly braces

There were no curly braces ({}) around the specified class, structure, or union initializer.


Compiler Error C2075

'identifier' : array initialization needs curly braces

There were no curly braces ({}) around the specified array initializer.

The following is an example of this error:

int i[] = 1, 2, 3 };     // error
int i[] = { 1, 2, 3 };   // OK


Compiler Error C2077

non-scalar field initializer 'identifier'

You tried to initialize a bit field with a struct, union, array, or class (a nonscalar). You can only initialize a bit field with an integer or floating point value (a scalar).


Compiler Error C2078

too many initializers

The number of initializers exceeded the number of objects to be initialized.


Compiler Error C2079

'identifier' uses undefined class/struct/union 'name'

The specified identifier was declared as a class, structure, or union that was not defined.

This error can be caused by initializing an anonymous union.


Compiler Error C2081

'identifier' : name in formal parameter list illegal

The specified identifier caused a syntax error.

This error can be caused by using the old style for the formal parameter list. The type of formal parameters must be specified in the formal parameter list.

The following is an example of this error:

void func( int i, j )  // error, no type specified for j
{
}


Compiler Error C2082

redefinition of formal parameter 'identifier'

A formal parameter to a function was redeclared within the function body.


Compiler Error C2083

struct/union comparison illegal

A structure or union was directly compared with another user-defined type.

A user-defined type cannot be compared with another user-defined type unless a comparison operator has been defined or a conversion to a scalar type exists.

The following is an example of this error:

struct A
{
   int i;
} a, b;
void func()
{
   if( a == b );   // error, structure comparison
}


Compiler Error C2084

function 'function' already has a body

The function has already been defined.


Compiler Error C2085

'identifier' : not in formal parameter list

The identifier was declared in a function definition but not in the formal parameter list.

A common cause of this error is the omission of a semicolon (;) at the end of a function prototype, as in:

void func1( void )
void main( void )
{
}

With the semicolon missing, func1() is taken to be a function definition, not a prototype. This means the function main() is being defined within func1(). Error C2085 is generated for the identifier main.

This is an error in ANSI C only.


Compiler Error C2086

'identifier' : redefinition

The given identifier was defined more than once, or a subsequent declaration differed from a previous one.

The following examples generate this error:

int a;
char a;
main()
{
}
main()
{
  int a;
  int a;
}

The following is an error in C++ but not in ANSI C:

int a;
int a;
main()
{
}


Compiler Error C2087

'identifier' : missing subscript

The definition of an array with multiple subscripts was missing a subscript value for a dimension other than the first dimension.

The following is an example of this error:

int func(a)
    char a[10][];         // error
    { }
int func(a)
    char a[][5];          // OK
    { }


Compiler Error C2088

'operator' : illegal for class-key

The specified operator was not defined for the class, structure, or union.

This error can be eliminated by defining a conversion to convert the operands to the type for which the operator is defined. Alternatively, an overloaded conversion operator can be defined.

An example of this error and two solutions are:

class A
{
public:
   int i;
} a;
int i = 1 + a;       // this line causes the error
class B
{
public:
   operator int() { return i; }
   int i;
} b;
int j = 1 + b;       // OK, uses conversion operator
class C
{
public:
   int operator+( int j ) { return (j+i); }  // solution
   int i;
} c;
int k = c + 1;       // OK, uses overloaded operator+
+ c;                 // still an error, no conversion
                     // operator defined for class C

Note that the last line requires that a conversion operator be defined since overloaded operators cannot be defined for built-in types.


Compiler Error C2089

'identifier' : 'class-key' too large

The specified structure or union was larger than 64K.

A structure or union cannot be larger than 64K.


Compiler Error C2090

function returns array

A function cannot return an array. It can return a pointer to an array.


Compiler Error C2091

function returns function

A function cannot return a function. It can return a pointer to a function.


Compiler Error C2092

array element type cannot be function

Arrays of functions are not allowed. Arrays of pointers to functions are allowed.


Compiler Error C2093

'variable1' : cannot be initialized using address of automatic variable 'variable2'

The program tried to use the address of an automatic variable in the initializer of a static item, as in the following example:

func()
{
    int i;
    static int *ip=&i;    // error
}


Compiler Error C2094

label 'identifier' was undefined

A goto label was found, but the specified label did not exist in the same function.


Compiler Error C2095

'function' : actual parameter has type 'void' : parameter 'number'

An attempt was made to pass a void argument to a function. The given number indicates which parameter was in error.

Formal parameters and parameters to functions cannot have type void. They can, however, have type void * (pointer_to_void).


Compiler Error C2097

illegal initialization

One of the following was illegally attempted:

  • Initialization of a variable using a nonconstant value

  • Initialization of a short address with a long address

  • Initialization of a local structure, union, or array with a nonconstant expression when compiling with /Za

  • Initialization with an expression containing a comma operator (,)

  • Initialization with an expression that is neither constant nor symbolic


Compiler Error C2098

expression is not an address

An address was expected as the initialization expression.


Compiler Error C2099

initializer is not a constant

The initializer was not a constant.

The following is an example of this error when compiled as C:

int i, j;
int *p;
j = i();    // error, i() is not constant
j = *p;     // error, *p is not a constant


Compiler Errors C2100 through C2199

The following topics cover compiler errors C2100 through C2199.


Compiler Error C2100

illegal indirection

The indirection operator (*) was applied to a nonpointer value.


Compiler Error C2101

'&' on constant

The address-of operator (&) did not have an l-value as its operand.


Compiler Error C2102

'&' requires l-value

The address-of operator (&) must be applied to an l-value expression.


Compiler Error C2103

'&' on register variable

An attempt was made to use the address of a register variable.


Compiler Error C2104

'&' on bit field ignored

An attempt was made to use the address of a bit field.


Compiler Error C2105

'operator' needs l-value

The given operator did not have an l-value operand.


Compiler Error C2106

'operator' : left operand must be l-value

The left operand of the given operator was not an l-value.


Compiler Error C2107

illegal index, indirection not allowed

A subscript was applied to an expression that did not evaluate to a pointer.


Compiler Error C2108

subscript is not of integral type

A nonintegral expression was used in an array subscript.


Compiler Error C2109

subscript requires array or pointer type

A subscript was used on a variable that was not an array.


Compiler Error C2110

cannot add two pointers

An attempt was made to add one pointer to another using the plus operator (+).


Compiler Error C2111

pointer addition requires integral operand

An attempt was made to add a nonintegral value to a pointer using the plus operator (+).


Compiler Error C2112

pointer subtraction requires integral or pointer operand

An attempt was made to subtract pointers that did not point to the same type.


Compiler Error C2113

pointer can only be subtracted from another pointer

The right operand in a subtraction operation using the minus operator (-) was a pointer, but the left operand was not.


Compiler Error C2114

'operator' : pointer on left; needs integral value on right

The left operand of the given operator was a pointer. Therefore the right operand must be an integral value.


Compiler Error C2115

'identifier' : incompatible types

An expression contained incompatible types.


Compiler Error C2116

function parameter lists differed

The parameters in the default parameter list did not match the formal parameter list.


Compiler Error C2117

'identifier' : array bounds overflow

Too many initializers were present for the given array.

Make sure that the array elements and initializers match in size and quantity.

This error can be caused by not leaving space for the null terminator in a string.

The following is an example of this error:

char abc[4] = "abcd"; // error, array contains 5 members


Compiler Error C2118

negative subscript or subscript is too large

A value defining an array size was negative or exceeded the maximum array size.


Compiler Error C2119

typedef types both define indirection

Two typedef types were used to declare an item, and both typedef types had indirection.

For example, the declaration of p in the following example is illegal:

typedef int *p_int;
typedef short *p_short;
p_short p_int p;        // error


Compiler Error C2120

'void' illegal with all types

The void type was used in a declaration with another type.


Compiler Error C2121

'#' : invalid character : possibly the result of a macro expansion

An illegal pound character (#) was found. It may have been inserted by an incorrectly formed macro using the token-pasting operator (##) instead of the stringizing operator (#).


Compiler Error C2122

'identifier' : prototype parameter in name list illegal

The specified parameter was not a legal type.

User-defined types are not supported in ANSI C.


Compiler Error C2124

divide or mod by zero

A constant expression was evaluated and found to have a zero denominator.


Compiler Error C2125

'identifier' : allocation exceeds 64K

The given item exceeded the size limit of 64K.


Compiler Error C2126

'operand' : incorrect operand

The specified operator was used on an enumeration.

The increment and decrement operators (++ and --) are not defined for enumerated types.


Compiler Error C2127

parameter allocation exceeds 32K

The storage space required for the parameters to a function exceeded the limit of 32K.


Compiler Error C2129

static function 'function' declared but not defined

A forward reference was made to a static function that was never defined.

A function declared static must be defined within file scope. If the function is defined in another file, it should be declared with the keyword extern.


Compiler Error C2130

#line expected a string containing the filename, found 'token'

The optional token following the line number on a #line directive was not a string.


Compiler Error C2131

more than one memory attribute

More than one memory attribute ( __near, __far, __huge, or __based) was applied to an item, as in the following example:

typedef int __near nint;
nint __far a;              // error


Compiler Error C2132

syntax error : unexpected identifier

An identifier appeared in a syntactically illegal context.


Compiler Error C2133

'identifier' : unknown size

An unsized array was declared as a member of a class, structure, union, or enumeration.

Unsized member arrays are not allowed when the /Za (ANSI) switch has been chosen.

The following is an example of this error:

struct X
{
   int a[0]; // error, unsized array
};


Compiler Error C2134

'identifier' : struct/union too large

The size of a structure or union exceeded the compiler limit of 64K.


Compiler Error C2135

'identifier' : illegal bit field operation

The address of the specified bit field was taken.

The address-of operator (&) cannot be applied to a bit field.

The following is an example of this error:

struct S
{
   int i : 1;
   int j;
};
void main()
{
   &S::i;      // error, address of a bit field
   &S::j;      // OK
}


Compiler Error C2136

'function' : prototype must have parameter types

A function prototype declaration had formal parameter names, but no types were provided for the parameters.

A formal parameter in a function prototype must either have a type or be represented by an ellipsis (...) to indicate a variable number of parameters and no type checking.

One cause of this error is a misspelling of a type name in a prototype that does not provide the names of the formal parameters.


Compiler Error C2137

empty character constant

The illegal empty character constant (' ') was used.


Compiler Error C2138

illegal to define an enumeration without any members

An empty enumeration was defined.

An enumeration must have at least one member.

This is an error when the /Za (disable Microsoft extensions) switch has been selected.


Compiler Error C2139

type following 'identifier' is illegal

Two types were used in the same declaration, as in:

int double a;    // error


Compiler Error C2140

parameter cannot be function type

A function was illegally declared as a formal parameter of another function.


Compiler Error C2141

value out of range for enum constant

An enumeration constant had a value outside the range of values allowed for an integer type.


Compiler Error C2142

function declarations differ, variable parameters specified only in one of them

One declaration of the function contained a variable parameter list, but another declaration did not.

This causes an error in C when the /Za (ANSI) switch is chosen.

The following is an example of this error:

void func();
void func( int, ... );    // error


Compiler Error C2143

syntax error : missing 'token1' before 'token2'

A syntax error is an error in the use of the language. A token is a language element such as a keyword or operator. Roughly translated, anything that is not whitespace (spaces, tabs, line feeds, comments, and so on) is a token.

The compiler expects certain language elements to appear before or after other elements. For instance, an if statement requires that the first non-whitespace character following the word if must be an opening parenthesis. If anything else is used, the compiler cannot “understand” the statement. For example:

if j < 25    // syntax error : missing '(' before 'j'

This error can also be caused by a missing closing brace ‘}’, right parenthesis ‘)’, or semicolon ‘;’. The missing token may belong on the line above where the error was actually detected and reported.

This error can also be caused by an invalid tag in a class declaration. The following are examples of these errors:

class X
{
   int member
} x;          // error, missing ; on previous line
class + {};   // error, + is an invalid tag name

This error can also be caused by placing a label by itself without being attached to a statement. If you need to place a label by itself, for example at the end of a compound statement, it can be attached to a null statement.

The following is an example of this error:

void func1()
{
   end:      // error
}            // this line is not a statement
void func2()
{
   end:      // OK
    ;        // this label attached to null statement
}

This error can also be caused when the ANSI compatibility option (/Za) is in effect and the source code contains single line comments.

The following is an example of this error:

int i;    // syntax error : missing ';' before 'division operator'
int j;    /* no error */

In the first case, the first single line comment character, ‘/’, is interpreted as a division operator since single line comments are not valid according to the ANSI C language standard. However, single line comments are legal in the C++ language.

Tips

  • Check the C/C++ Language Quick Reference to determine where the code is syntactically incorrect.

  • Since this error is sometimes detected after the line where the error actually occurred, check a few lines up in the code for the syntax error.

  • Do not use the /Za compiler switch if you want to use single line comments in a C language file.


Compiler Error C2144

syntax error : missing 'token' before type 'type'

The compiler expected the given token to appear before the given type name.

This error can be caused by a missing closing brace (}), right parenthesis, or semicolon (;).


Compiler Error C2145

syntax error : missing 'token' before identifier

The compiler expected the given token to appear before an identifier.

This error can be caused by a missing semicolon (;) after the last declaration in a block.


Compiler Error C2146

syntax error : missing 'token' before identifier 'identifier'

The compiler expected the given token to appear before the given identifier.

Tips

This error is usually preceeded by error C2065. The most typical cause of this error is a typographical problem. For example:

void main(void)
{
   intt x; //Syntax error: missing semicolon before 'x'
}


Compiler Error C2147

'identifier' : const automatic array must be fully initialized

The specified array was declared as const but one or more elements were not initialized.

All elements of a const array must be initialized when it is defined.

The following is an example of this error:

const int arr[10] = { 1, 2}; // error


Compiler Error C2148

array too large

An array exceeded the maximum legal size of 64K.

Either reduce the size of the array or declare it with __huge.


Compiler Error C2149

'identifier' : named bit field cannot have zero width

The given named bit field had zero width. Only unnamed bit fields are allowed to have zero width.


Compiler Error C2150

'identifier' : bit field must have type 'int', 'signed int', or 'unsigned int'

The ANSI C standard requires bit fields to have types of int, signed int, or unsigned int. This message appears only when compiling with the /Za option.


Compiler Error C2151

more than one language attribute

More than one keyword specifying a calling convention ( __cdecl, __fortran, __pascal, or __fastcall) for a function was given.


Compiler Error C2152

'identifier' : pointers to functions with different attributes

An attempt was made to assign a pointer to a function declared with one calling convention (__cdecl, __fortran, __pascal, or __fastcall) to a pointer to a function declared with a different calling convention.


Compiler Error C2153

hex constants must have at least one hex digit

The hexadecimal constants 0x, 0X, and \x are illegal. At least one hexadecimal digit must follow the x or X.


Compiler Error C2154

'segment' : does not refer to a segment name

A segment must be allocated when a based variable is declared unless it is extern and uninitialized.


Compiler Error C2155

'?' : invalid left operand, expected arithmetic or pointer type

Your code includes an expression on the left hand side of a '?' that cannot be compared to zero (0). You must use an arithmetic or pointer type expression which can be compared to zero (0).


Compiler Error C2156

pragma must be outside function

A pragma that must be specified at a global level (that is, outside a function body) occurred within a function.

The following is an example of this error:

main()
{
  #pragma optimize( "l", on )   // error
}


Compiler Error C2157

'function' : must be declared before use in pragma list

The function name in the list of functions for an alloc_text pragma was not declared prior to being referenced in the list.


Compiler Error C2158

'identifier' : is a function

The given identifier was specified in the list of variables in a same_seg pragma but was previously declared as a function.


Compiler Error C2159

more than one storage class specified

A declaration contained more than one storage class, as in:

extern static int i;      // error


Compiler Error C2160

'##' cannot occur at the beginning of a macro definition

A macro definition began with a token-pasting operator (##), as in:

#define mac(a,b) ##a    // error


Compiler Error C2161

'##' cannot occur at the end of a macro definition

A macro definition ended with a token-pasting operator (##), as in:

#define mac(a,b) a##    // error


Compiler Error C2162

expected macro formal parameter

The token following a stringizing operator (#) was not a formal parameter name.

The following is an example of this error:

#define print(a) printf(#b)    // error


Compiler Error C2163

'function' : not available as an intrinsic function

A function specified in the list of functions for an intrinsic or function pragma is not one of the functions available in intrinsic form.


Compiler Error C2164

'function' : intrinsic function not declared

The given function was not declared before being used in an intrinsic pragma. This error appears only when compiling with the /Oi option.


Compiler Error C2165

'keyword' : cannot modify pointers to data

The __fortran, __pascal, __cdecl, or __fastcall keyword was used illegally to modify a pointer to data, as in the following example:

char __pascal *p;   // error


Compiler Error C2166

l-value specifies const object

An attempt was made to modify an item declared with const type.


Compiler Error C2167

'function' : too many actual parameters for intrinsic function

A reference to a function declared as intrinsic contained too many actual parameters.


Compiler Error C2168

'function' : too few actual parameters for intrinsic function

A reference to a function declared as intrinsic contained too few actual parameters.


Compiler Error C2169

'function' : intrinsic function, cannot be defined

An attempt was made to provide a function definition for a function already declared as an intrinsic.


Compiler Error C2170

'identifier' : not declared as a function, cannot be intrinsic

The intrinsic pragma was used for an item other than a function or for a function that does not have an intrinsic form.


Compiler Error C2171

'operator' : illegal operand

The given unary operator was used with an illegal operand type, as in the following example:

int (*fp)();
double d, d1;

fp++;           // error
d = ~d1;        // error


Compiler Error C2172

'function' : actual parameter is not a pointer : parameter number

An attempt was made to pass an parameter that was not a pointer to a function that expected a pointer. The given number indicates which parameter was in error.


Compiler Error C2173

'function' : actual parameter is not a pointer : parameter number1, parameter list number2

An attempt was made to pass a nonpointer parameter to a function that expected a pointer.

This error occurs in calls that return a pointer to a function. The first number indicates which parameter was in error; the second number indicates which parameter list contained the invalid parameter.


Compiler Error C2174

'function' : actual parameter has type 'void' : parameter number1, parameter list number2

An attempt was made to pass a void parameter to a function. Formal parameters and parameters to functions cannot have type void. They can, however, have type void* (pointer to void).

This error occurs in calls that return a pointer to a function. The first number indicates which parameter was in error; the second number indicates which argument list contained the invalid parameter.


Compiler Error C2175

'locale' : invalid locale

The specified locale is not valid. See Language and Country Strings in the Run-Time Library Reference for a list of supported locales.


Compiler Error C2177

constant too big

A constant value was too large to be represented in the type to which it was assigned.


Compiler Error C2178

'identifier' : storage class for same_seg variables must be extern

The given variable was specified in a same_seg pragma, but the variable was not declared with extern storage class.


Compiler Error C2179

'identifier' : was used in same_seg, but storage class is no longer extern

The given variable was specified in a same_seg pragma, but the variable was redeclared with a storage class other than extern.


Compiler Error C2180

controlling expression has type 'void'

The controlling expression in an if, while, for, or do statement was either a function with void return type or an expression cast to void.


Compiler Error C2181

illegal else without matching if

You code includes an else without a matching if. Make sure each else is matched with an if.


Compiler Error C2182

'identifier' : illegal use of type 'void'

The given variable was declared with the keyword void, which can be used only in function declarations.


Compiler Error C2183

syntax error: translation unit is empty

A source file was empty after preprocessing.


Compiler Error C2184

illegal return of a 'void' value

The function did not return a value.

The function was declared as returning a nonvoid value, but the return statement did not return a value.


Compiler Error C2185

'identifier' : illegal based allocation

An automatic (local) or register variable was declared with the __based modifier.

Only global variables can be declared as __based.


Compiler Error C2186

'operand' : illegal operand of type 'void'

The specified operator had a void operand.

The following is an example of this error:

void func1( void );
int  func2( void );
int i = 2 + func1();   // error, func1() is type void
int j = 2 + func2();   // OK, both operands are type int


Compiler Error C2188

'number' : too big for wide character

The given number is too large to be held in the wide-character type.

Choose a larger type to hold the given value.


Compiler Error C2189

#error : string

An #error directive was encountered.

The string is the descriptive text supplied in the directive.


Compiler Error C2190

first parameter list longer than second

The function was declared a second time with a shorter parameter list.

C does not support overloaded functions.

The following is an example of this error:

void func( int, float );
void func( int,  );        // error, different parameter list


Compiler Error C2191

second parameter list longer than first

The function was declared a second time with a longer parameter list.

C does not support overloaded functions.

The following is an example of this error:

void func( int );
void func( int, float ); // error, different parameter list


Compiler Error C2192

parameter 'number' declaration different

The function was declared a second time with a different parameter list.

C does not support overloaded functions.

The following is an example of this error:

void func( float, int );
void func( int, float ); // error, different parameter list


Compiler Error C2193

'identifier' : already in a segment

A function was placed in two different segments using the alloc_text and code_seg pragmas.

The following is an example of this error:

extern "C" void foo();
#pragma alloc_text(MYCODE, foo)
#pragma code_seg("MYCODE2")
extern "C" void foo()
{               // error
}


Compiler Error C2194

'identifier' : is a text segment

A segment name was used with the data_seg pragma after it had already been used with the code_seg pragma.

The following is an example of this error:

#pragma code_seg("MYCODE")
#pragma data_seg("MYCODE")   // error


Compiler Error C2195

'identifier' : is a data segment

A segment name was used with the code_seg pragma after it had already been used with the data_seg pragma.

The following is an example of this error:

#pragma data_seg("MYDATA")
#pragma code_seg("MYDATA")   // error


Compiler Error C2196

case value 'value' already used

A case value in a switch statement can be used only once.

The following is an example of this error:

void f()
{
    int i;
    switch( i )
    {
    case 0:
        break;
    case 0:    // error, case value '0' already used
        break;
    }
}


Compiler Error C2197

'identifier' : too many actual parameters

The specified function was called with too many parameters, or the function declaration was incorrect.

The following is an example of this error:

void func( int );
main()
{
   func( 1, 2 );   // error, two actual parameters
}


Compiler Error C2198

'identifier' : too few actual parameters

The specified function was called with too few parameters, or the function declaration was incorrect.

The following is an example of this error:

void func( int, int );
main()
{
   func( 1 );   // error, only one actual parameter
}


Compiler Error C2199

syntax error : found 'identifier (' at global scope (was a declaration intended?)

The specified context caused a syntax error.

This error can be caused by incorrect declaration syntax.

The following is an example of this error:

struct S
{
public:
   int i;
   S( int si ) { i = si; }
};
S(1) s; // error, incorrect syntax
S s(1); // OK


Compiler Errors C2200 through C2299

The following topics cover compiler errors C2200 through C2299.


Compiler Error C2200

'function' : function has already been defined

A function name passed as a parameter in an alloc_text pragma has already been defined.


Compiler Error C2201

'identifier' : must have external linkage in order to be exported/imported

The specified static identifier was exported.

The following is an example of this error:

__declspec(dllexport) static void func() {}  // error, func() is static
__declspec(dllexport) void func() {}         // OK


Compiler Error C2202

'function' : not all control paths return a value

The specified function can potentially not return a value.

The following is an example of this error:

int func1( int i )
{
   if( i ) return 3;  // error, nothing returned if i == 0
}

To fix this error, modify the code so that all paths assign a return value to the function:

int func1( int i )
{
   if( i ) return 3;
   else return 0;     // OK, always returns a value
}

It is possible that your code may contain a call to a function that never returns, as in the following example:

int gloo()
{
   if(...)
     return 1;
   else if(...)
     return 0;
   else
     fatal();
}

This code also generates an error, because the compiler does not know that fatal never returns. To prevent this code from generating an error message, declare fatal using __declspec(noreturn).


Compiler Error C2203

delete operator cannot specify bounds for an array

The delete operator can only delete an entire array; it cannot delete parts or specific members of the array. This error is generated only with the /Za ANSI-compatibility option.

This was not an error in C++ 2.0 but is an error in C++ 2.1.

The following statement generates this error:

delete [4] ArrayOfObjects;   // error


Compiler Error C2204

'identifier' : type definition found within parentheses

The specified type was defined in prototype scope or as an operand.

The following is an example of this error:

( struct S {}; );  // error


Compiler Error C2205

'identifier' : cannot initialize extern variables with block scope

A variable with extern storage class cannot be initialized in a function.


Compiler Error C2206

'function' : typedef cannot be used for function definition

A typedef was used to define a function type.

For example:

typedef int functyp();
functyp func1 {};        // error


Compiler Error C2207

'member' in struct/union 'tag' has a zero-sized array

The given member in the structure or union contains an array that does not have a subscript or that has a zero subscript. This kind of array is legal only as the last member of a structure or union.


Compiler Error C2208

'type' : no members defined using this type

An enumeration, structure, or union was defined without any members. This is an error only when compiling for C++ with the ANSI compatibility option (/Za).

This error can be caused by porting C code using nested structs to C++. Rewriting the code to use C++ mechanisms will eliminate this error. The following example shows C and C++ style structs. Note that the first C struct, if compiled for C++, declares a nested struct, Struct::ToBeIncluded, which is not the same as ::ToBeIncluded.

struct ToBeIncluded {
    int i;
};

#ifndef __cplusplus
struct Struct {     //C struct defined using /Ze extensions
    float x;
    struct ToBeIncluded;     // MS-C style struct injection
    float y;
};                           // error under /Za ANSI compatibility
#else
struct Intermediate {        // revised C++ struct
    float x;
};

struct Struct                // C++ style
    :   public Intermediate,
        public ToBeIncluded
{
    float y;
};                           // Always OK for C++
#endif


Compiler Error C2212

'identifier' : __based not available for pointers to functions

Pointers to functions cannot be declared as __based.

If you need code-based data, use the __declspec keyword or the data_seg pragma.


Compiler Error C2213

'modifier' : illegal argument to __based

The argument given to the __based keyword is invalid.

The following is an example of this error:

int i;
char __based(i) *p;      // error


Compiler Error C2217

'attribute1' must be used with 'attribute2'

The first function attribute requires the use of the second attribute.

Some causes for this error include:

  • An interrupt function explicitly declared as near. Interrupt functions must be declared as far.

  • An interrupt function that is declared with the __fortran, __pascal, or __fastcall attribute. Functions declared with the __interrupt attribute must use C calling conventions.

  • __pascal, or __fastcall attribute. These functions must use C calling conventions. Remove the __fortran, __pascal, or __fastcall attribute from the function declaration.


Compiler Error C2218

type in __based construct must be 'void'

Only types based on void are legal in 32-bit targets.


Compiler Error C2219

syntax error : type qualifier must be after '*'

Either const or volatile appeared where a type or qualifier is not permitted, as in:

int (const *p);    // error


Compiler Error C2220

warning treated as error - no object file generated

When the compiler option /WX is used, the first warning generated by the compiler causes this error message to be displayed.

Either correct the condition that caused the warning or compile at a lower warning level or without /WX.


Compiler Error C2221

'.' : left operand points to class/struct/union. use '–>'

The left operand of the member-of operator (.) must be a class (or structure or union), but not a pointer to a class type.

The class member access operator (->) can be used with a pointer to a class, structure, or union.


Compiler Error C2222

'->' : left operand has class/struct/union type, use '.'

The left operand of the class member access operator (->) must be a pointer to a class (or structure or union) type but not a class type.

The member-of operator (.) can be used with a class, structure, or union type.


Compiler Error C2223

left of '->identifier' must point to class/struct/union

The left operand of the member access operator (->) is not a pointer to a class, structure, or union type.

This error can occur when the left operand is an undefined variable. Undefined variables have type int.


Compiler Error C2224

left of '.identifier' must have class/struct/union type

The left operand of the member-of operator (.) is not a class, structure, or union type.

This error can occur when the left operand is an undefined variable. Undefined variables have type int.


Compiler Error C2226

syntax error : unexpected type 'type'

A syntax error occurred before, or in, the given type specifier.

The following is an example of this error:

int func1( int, ... , float ); // error, misplaced ellipsis
int func2( int, float, ... );  // OK


Compiler Error C2227

left of '->identifier' must point to class/struct/union

The left side of the specified class member access operator (->) was not a pointer to a class, structure, or union.

The following is an example of this error:

int  *pInt;
struct S
{
public:
    int member;
} *pS;
void main()
{
    pInt->member = 0;   // error, pInt points to an int
    pS->member = 0;     // OK, pS points to a structure S
}


Compiler Error C2228

left of '.identifier' must have class/struct/union type

The left side of the specified class member access operator (.) was not a class (or structure or union) type.

The following is an example of this error:

int i;
struct S
{
public:
    int member;
} s, *ps;
void main()
{
   i.member = 0;   // error, i is not a class type
   ps.member = 0;  // error, ps is a pointer to a structure
   s.member = 0;   // OK, s is a structure type
   ps->member = 0; // OK, ps points to a structure S
}


Compiler Error C2229

type 'identifier' has an illegal zero-sized array

The specified member of the structure or bit field contained a zero-sized array.

The following is an example of this error:

struct S
{
   int a[0];  // error, zero-sized array
   int b[1];  // OK
};


Compiler Error C2230

'operator' : indirection to different types

The pointer expressions used with the given operator had different base types.

The pointer expressions were used without conversion. This causes a warning in ANSI C but is an error in C++.

The following is an example of this error:

struct ts1 *s1;
struct ts2 *s2;
s2 = s1;   // error


Compiler Error C2231

'.' : left operand points to 'class-key', use '–>'

The left operand of the member selection operator (.) was a pointer to a class, structure, or union.

The left operand of the member selection operator must be a class, structure, or union.

The following is an example of this example:

struct S
{
public:
    int member;
} s, *ps;
void main()
{
   ps.member = 0;  // error, ps points to structure S
   ps->member = 0; // OK, ps points to a structure S
   s.member = 0;   // OK, s is a structure type
}


Compiler Error C2232

'–>' : left operand has 'class-key' type, use '.'

The class member access operator (->) was used on a nonpointer.

The pointer form of the class member access operator can only be used with a pointer to a class, structure, or union. The dot (.) form of the operator should be used with a class, structure, or union type.

The following is an example of this error:

struct X
{
    int member;
} x, *px;
void main()
{
    x->member = 0;   // error, x is not a pointer
    px->member = 0;  // OK, px is a pointer to an X
    x.member = 0;    // OK
}


Compiler Error C2233

'identifier' : arrays of objects containing zero-size arrays are illegal

The specified object contained a zero-sized array. Each object in an array must contain at least one element.


Compiler Error C2234

'name' : arrays of references are illegal

An array of references was declared.

Since pointers to references are not allowed, arrays of references are not possible. A pointer should be used to implement the array.


Compiler Error C2235

';' in formal parameter list

A semicolon (;) was found in a formal parameter list.

The error is usually caused by using a semicolon instead of a comma (,) to separate parameters in a formal parameter list.

The following is an example of this error:

void func( int i; float f );   // error, uses semicolon
void func( int i, float f );   // OK, uses comma


Compiler Error C2236

unexpected 'class-key' 'identifier'

The specified identifier was already defined as a type and cannot be overridden by another user-defined type.


Compiler Error C2238

unexpected token(s) preceding 'token'

An incorrect token, or tokens, was found before the specified token.

This error can be caused by an invalid name in a bit-field declaration.

The following is an example of this error:

struct bits
{
   int field1 : 16;
   int 9      : 16;  // error, 9 is not a valid name
};


Compiler Error C2239

unexpected token 'token' following declaration of 'identifier'

An unexpected token was found in the specified declaration.

The following is an example of this error:

int i 8;   // error, missing =
int j = 7; // OK


Compiler Error C2240

unexpected 'token' following formal list (only modifiers are allowed)

The specified token was found after a formal parameter list.

The following is an example of this error:

void func() int;  // error
void func();      // OK


Compiler Error C2241

'identifier' : member access is restricted

There was an attempt to access a private or protected member function or data.

If the program needs to access this member, change the object access level or make the member a friend of the function that needs to be accessed.


Compiler Error C2242

typedef name cannot follow class/struct/union

A typedef name was used at the end of a qualified name.


Compiler Error C2243

'conversion type' conversion from 'type1' to 'type2' exists, but is inaccessible

A pointer to a derived class was converted to a pointer to a base class, but the derived class inherited the base class with private or protected access.

The following is an example of this error:

class B {};
class D : private B {};

D d;
B *p = &d;      // error


Compiler Error C2244

'identifier' : unable to resolve function overload

The specified overloaded function call was ambiguous.

The following is an example of this error:

int func( char );
int func( int );
void main ()
{
   +func;       // error, can't resolve which func to use
   +func( 0 );  // OK
}


Compiler Error C2245

nonexistent function 'identifier' specified as friend

The specified identifier was not a function.

Only a function can be specified as a friend.

The following is an example of this error:

class C
{
public:
   int i;                  // i is not a function
   void func();
};
class S
{
public:
   friend void C::i();     // error
   friend void C::func();  // OK
};


Compiler Error C2246

'identifier' : illegal static data member in locally defined class

The specified member of a class, structure, or union with local scope was declared as static.

The following is an example of this error:

void func( void )
{
   class A
   {
 static int i;    // error, i is local to func
   };
};
class B
{
   static int i;       // OK
};


Compiler Error C2247

'identifier' not accessible because 'class' uses 'specifier' to inherit from 'class'

The specified identifier was inherited from a class declared with private or protected access.

The following is an example of this error:

class A
{
public:
   int i;
};
class B : private A {};    // B inherits a private A
class C : public B {} c;   // so even though C's B is public
int j = c.i;               // error, i not accessible


Compiler Error C2248

'member' : cannot access 'access' 'member' declared in class 'class'

The specified private or protected member of a class, structure, or union was accessed.

Tips

This error can be caused by attempting to access a member that is declared as private or protected, or by accessing a public member of a base class that is inherited with private or protected access. The member should be accessed through a member function with public access or should be declared with public access. The following is an example of this error:

class X
{
public:
   int  m_pubMemb;
   void setPrivMemb( int i ) { m_privMemb = i; }
protected:
   int  m_protMemb;
private:
   int  m_privMemb;
} x;

class Y : X {} y;    // default access to X is private

void main()
{
   x.m_pubMemb;      // OK, m_pubMemb is public
   x.setPrivMemb( 0 ); // OK, uses public access function
   x.m_protMemb;     // error, m_protMemb is protected
   x.m_privMemb;     // error, m_privMemb is private
   y.m_pubMemb;      // error, Y inherits X as private
   y.setPrivMemb( 0 ); // error, Y inherits X as private
}


Compiler Error C2249

'identifier' : no accessible path to access member declared in virtual base 'class'

The specified inherited member was inherited from a nonpublic virtual base class or structure.

The following is an example of this error:

class A
{
private:
   void privFunc( void ) {};
public:
   void pubFunc( void ) {};
};
class B : virtual public A {} b;
void main( void )
{
   b.privFunc();        // error, private member of A
   b.pubFunc();         // OK
}


Compiler Error C2250

'identifier' : ambiguous inheritance of 'class::member'

The derived class inherited more than one override of a virtual function of a virtual base. These overrides are ambiguous in the derived class.

The following is an example of this error:

struct V { virtual void vf(); };
struct A : virtual V { void vf(); };
struct B : virtual V { void vf(); };
struct D : A, B {};                   //error


Compiler Error C2251

'identifier' : defined but not declared

The specified destructor was defined, but not declared in the class body. A compiler-generated destructor is used if a destructor declaration is not in the class body.

The following is an example of this error:

class C
{
  C();     // only a constructor is declared
};

C::C() {}  // OK, constructor is defined

C::~C()    // undeclared destructor definition
{          // error on this line
}


Compiler Error C2252

'identifier' : pure specifier can only be specified for functions

The given nonfunction was specified as pure virtual.

Only member functions specified as virtual can be declared with a pure specifier.

The following is an example of this error:

class A
{
   virtual int i = 0;          // error, i is an int
   virtual void func() = 0;    // OK, func is a function
};


Compiler Error C2253

'function' : pure specifier only applies to virtual function – specifier ignored

The specified nonvirtual function was specified as pure virtual.

The specifier was ignored.

The following is an example of this error:

class A
{
public:
  void func1() = 0;          // error, not virtual
  virtual void func2() = 0;  // OK
};


Compiler Error C2254

'function' : pure specifier not allowed on friend functions

The specified friend function was specified as pure virtual.

The following is an example of this error:

class A
{
public:
   friend void func1() = 0;   // error, func1 is friend
   void virtual func2() = 0;  // OK, pure virtual
   friend void func3();       // OK, friend not virtual nor
};                            //     pure
void func1() {};
void func3() {};


Compiler Error C2255

'function' : a friend function can only be declared in a class

The specified function was declared with the friend specifier outside of a class, structure, or union.

The following is an example of this error:

class A
{
private:
   void func1();
   friend void func2();
};
friend void func1() {};    // error
void func2() {};           // OK


Compiler Error C2256

illegal use of friend specifier on 'destructor'

The specified destructor was specified as a friend.

A destructor cannot be specifed as a friend.

The following is an example of this error:

class C
{
public:
   friend ~C(); // error
   ~C();        // OK
};


Compiler Error C2258

illegal pure syntax, must be '= 0'

A pure virtual function was declared with incorrect syntax.

The following is an example of this error:

class A
{
public:
   void virtual func1() = 1; // error, not = 0
   void virtual func2() = 0; // OK
};


Compiler Error C2259

'class' : cannot instantiate abstract class due to following members:

An object of the specified abstract class or structure was declared. This error is followed by one or more C4259 warnings specifying the abstract members.

A class (or structure) with one or more pure virtual functions cannot be instantiated. Each pure virtual function must be overridden in a derived class before objects of the derived class can be instantiated.

The following is an example of this error:

class V
{
public:
   void virtual func() = 0;
};
class A : public V {};
class B : public V
{
public:
   void func();
};
V v;  // error, V is an abstract class
A a;  // error, A inherits func() as pure virtual
B b;  // OK, B defines func()


Compiler Error C2260

function pointer cast to a data pointer

A pointer to a function was cast to a pointer to data.

This cast is not legal in ANSI C.

This cast is legal in C++ and is allowed by the Microsoft extensions (using the /Ze switch).


Compiler Error C2261

data pointer cast to a function pointer

A pointer to data was cast to a pointer to a function.

This cast is not legal in ANSI C.

This cast is legal in C++ and is allowed by the Microsoft extensions (using the /Ze switch).


Compiler Error C2262

'identifier' : cannot be destroyed

The specified identifier was not instantiated because an appropriate destructor was defined but not accessible.

The following is an example of this error:

class B
{
   ~B();
};
class D : public B {};
D d;         // error, B's destructor is private


Compiler Error C2264

'function' : error in function definition or declaration; function not called

Since the specified function was incorrectly defined or declared, it could not be called.

The following is an example of this error:

class C
{
public:
   operator int( int = 10 );    // incorrect declaration here
};
void main()
{
   int i;
   C c;
   i = c;                       // error
}


Compiler Error C2265

'identifier' : reference to a zero-sized array is illegal

The specified reference was declared for an array with zero size.

References can only be declared for arrays with nonzero, nonconstant bounds.


Compiler Error C2266

'identifier' : reference to a non-constant bounded array is illegal

The specified reference was declared for an array with a nonconstant bound.

References can only be declared for arrays with constant bounds.


Compiler Error C2267

'function' : static functions with block scope are illegal

The specified local function was declared as static.

Static functions must be declared with global scope.

The following is an example of this error:

void main()
{
    static int func1();    // error
}


Compiler Error C2268

'operation' : different const or volatile qualifiers

The given operation was performed on a variable that was defined as being const or volatile. As a result, the const or volatile item could be modified without being detected by the compiler.

This error often occurs when a pointer to an item declared as const or volatile is assigned to a pointer that was not declared as pointing to either of these type modifiers.

The following is an example of this error:

const  char *p = "abcde";
int    str( char *s );
str( p );                // error


Compiler Error C2270

'identifier' : modifiers not allowed on nonmember functions

The specified nonmember function was declared with a memory-model modifier.

Only functions that are members of a class, structure, or union can have memory-model modifiers.

The following is an example of this error:

void func1() __near;     // error, nonmember function
class C
{
public:
   void func2() __near;  // OK
};


Compiler Error C2271

'operator' : new/delete cannot have formal list modifiers

The specified operator was declared with a memory-model specifier.

A memory-model specifier cannot be specified for the new or delete operators.

The following is an example of this error:

class C
{
   void *operator new( unsigned ) __far;   // error
};


Compiler Error C2272

'function' : modifiers not allowed on static member functions

The specified static member function was declared with a memory- model specifier.

The following is an example of this error:

class C
{
public:
  static void func1() __far;  // error, func1 is static
  void func2() __far;         // OK
};


Compiler Error C2273

'type' : illegal as right side of '->' operator

The given type was specified on the right side of the class member access operator (->).

To access a user-defined type conversion, use the operator keyword between the -> operator and the type.

The following is an example of this error:

i = ClassPtr->int( a );           // error
i = ClassPtr->operator int( a );  // OK


Compiler Error C2274

'type' : illegal as right side of '.' operator

The given type was specified on the right side of the class member access operator (.).

To access a user-defined type conversion, use the operator keyword between the dot operator (.) and the type.

The following is an example of this error:

i = ClassName.int( a );           // error
i = ClassName.operator int( a );  // OK


Compiler Error C2275

'identifier' : illegal use of this type as an expression

The expression used the class member access operator (->) on the specified typedef identifier.

The following is an example of this error:

typedef struct S
{
    int mem;
} *S_t;
void func1( int *parm );
void func2()
{
    func1( &S_t->mem );   // error: S_t is a typedef
}


Compiler Error C2276

'operator' : illegal address of bound member function expression

The address of a virtual function was taken.

The following is an example of this error:

class A
{
public:
   virtual int func();
} a;
int (*pf)() = &a.func;   // error
class B
{
public:
   void mf()
   {
  &this->mf;       //error
   }
};


Compiler Error C2277

'identifier' : cannot take address of this member function

It is not possible to take the address of the member function.

The following is an example of this error:

class A
{
public:
   A();
};
(*pctor)() = &A::A;   // error


Compiler Error C2278

'function' : no function with C linkage found

The specified function was not found.

This error is caused by omitting the file containing the function definition from the project list or makefile, by not defining the function within the file scope, or by omitting the keyword extern in the function prototype.


Compiler Error C2279

cannot use braces to initialize default arguments

The following is an example of this error:

struct Point
{
   int x, y;
};
int f( Point p = { 1, 2 } );  // error 2279


Compiler Error C2280

missing '{' before identifier 'identifier'?

The expression caused a syntax error that was probably due to a missing opening brace ({).

The following is an example of this error:

int int_var;
void func( int a     // missing opening brace
   t_var = 1;        // error is called on this line
}


Compiler Error C2281

'identifier1' : is not a function, but contains <function returning>; 'identifier2' is unexpected

The declaration of the specified identifier used incorrect syntax.

The following is an example of this error:

int (*f)() a;      // error


Compiler Error C2282

'identifier1' is followed by 'identifier2' (missing ','?)

The declaration of the specified identifiers used incorrect syntax, probably due to a missing comma.

The following is an example of this error:

int *f g;          // error


Compiler Error C2283

'identifier' : pure specifier not allowed on unnamed class-key

The specified member function of an unnamed class or structure was illegally declared with a pure specifier.

The following is an example of this error:

struct
{
   virtual void func() = 0;   // error
};
struct S
{
   virtual void func() = 0;   // OK
};


Compiler Error C2284

unbalanced parenthesis found while processing a member function

The member function definition ended with a parenthesis instead of a curly brace.

The following is an example of this error:

class C {
public:
   void func()
   {
   );            // error, parenthesis instead of curly brace
};


Compiler Error C2285

pointers to members representation has already been determined - pragma ignored

A different representation was already specified for the class. The first representation was used.

The following is an example of this error.

class  __single_inheritance X;
class  __multiple_inheritance X;   // error


Compiler Error C2286

pointers to members of 'identifier' representation is already set to 'inheritance' – declaration ignored

A different pointer to members representation was already specified for the specified class.

The following is an example of this error.

class  __single_inheritance X;
class  __multiple_inheritance X;   // error


Compiler Error C2287

'class': inheritance representation: 'representation1' is less general than the required 'representation2'

A class was declared with a more simple representation than was required.

The following example causes this error when compiled using the "General-purpose always" representation method (/vmg):

class __single_inheritance X;

struct A { };
struct B { };
struct X : A, B { };  // error, X uses multiple inheritance


Compiler Error C2289

same type qualifier used more than once

A type qualifier (const, volatile, signed, or unsigned) was used more than once in the same type declaration or definition.

This is an error when Microsoft extensions are disabled (/Za), and a warning when extensions are enabled (/Ze).

The following is an example of this error:

volatile volatile int i;   // error


Compiler Error C2290

C++ asm syntax ignored. Use __asm.

The syntax for the specified C++ keyword is reserved for future use.

Rewrite the expression, omitting the keyword.


Compiler Error C2292

'identifier': best case inheritance representation: 'representation1' declared but 'representation2' required

The following example causes this error when the "Best-case always" representation method is chosen.

class __single_inheritance X;

struct A { };
struct B { };
struct X : A, B { };  // error, X uses multiple inheritance


Compiler Error C2293

'identifier': illegal to have a member variable as a __based specifier

Only pointers that are non-member variables can be specified as the base of the __based modifier.

class A
{
   static int *i;
   void __based(i) *bp; // error
};


Compiler Error C2294

'identifier': illegal argument to intrinsic function, parameter number

The specified parameter was invalid for the given function.


Compiler Error C2295

escaped 'character' : is illegal in macro definition

A macro definition may not contain the specified character in an escape sequence.


Compiler Error C2296

'operator' : bad left operand

The left operand of the given operator was illegal for that operator.


Compiler Error C2297

'operator' : bad right operand

The right operand of the given operator was illegal for that operator.


Compiler Error C2298

'operation' : illegal operation on pointer to member function expression

A pointer to member function expression can only be used to call the member function.

The following is an example of this error:

struct X {
    int mf() { return 0; }
};

X x;
int (X::*pmf)() = &X::mf;

int main()
{
    int (*pf)();
    pf = x.*pmf;   // error
    +(x.*pmf);     // error
    return 0;
}


Compiler Error C2299

'name' : globally qualified name illegal as right hand side of operator 'operator'

Only a member of a class, structure, or union used on the right hand side of the specifed member access operator.


Compiler Errors C2300 Through C2398

The following topics cover compiler errors C2300 through C2398.


Compiler Error C2300

'identifier' : class does not have a destructor called '~identifier'

The destructor for the specified class had a name different from a tilde (~) followed by the class name.


Compiler Error C2301

left of '->~identifier' must point to class/struct/union

The expression on the left side of the -> operator did not evaluate to a pointer to a class, structure, or union.


Compiler Error C2302

left of '.~identifier' must have class/struct/union type

The expression of the left side of the dot operator (.) was not a class, structure, or union.


Compiler Error C2303

left of '.identifier' must be an l-value

Only an l-value can be on the left side of the dot operator (.).


Compiler Error C2304

'type symbol' : unexpected tokens following type

The compiler was unable to recognize the tokens following the type. This error is similar to error C2239 except C2304 occurs within a function body.


Compiler Error C2305

'filename' does not contain debugging information for this module

The specified program database does not contain current debugging information for this module. Delete the file and recompile.


Compiler Error C2306

'filename' does not contain the most recent debugging information for this module

The specified program database file is not current. Delete it and recompile.


Compiler Error C2307

pragma pragma must be outside function if incremental compilation is enabled

Incremental compilation operates on a function-by-function basis. You must place the data_seg pragma between functions if you’re using incremental compilation.


Compiler Error C2308

concatenating mismatched wide strings

Both wide and non-wide character strings were specified in the arguments to a pragma. Either use wide character strings exclusively or use non-wide character strings exclusively.


Compiler Error C2309

catch handler expected a parenthesized exception declaration

A catch handler was defined without a parenthesized type.

The following is an example of this error:

#include <eh.h>
class C;
void main()
{
    try
    {
        throw "ooops!";
    }
    catch C  {}   // error
    catch( C ) {} // OK
}


Compiler Error C2310

catch handlers must specify one type

A catch handler specified zero, or more than one type.

The following is an example of this error:

#include <eh.h>
int main()
{
    try
    {
        throw "Out of memory!";
    }
    catch( int ,int)  // error, two types
    {
    }
    return 0;
}


Compiler Error C2311

'exception' : is caught by '...' on line number

The catch handler for the ellipsis (...) must be the last handler for any throw.

The following is an example of this error:

#include <eh.h>
//...
void main()
{
    try
    {
        throw "ooops!";
    }
    catch( ... ) {}  // ellipsis handler is not last catch for this throw
    catch( int ) {}
}


Compiler Error C2312

'exception1' : is caught by 'exception2' on line number

The specified exception type is handled by a previous handler. The type for the second catch is equivalent to the type of the first.

The following is an example of this error:

#include <eh.h>
//...
void main()
{
    try
    {
        throw "ooops!";
    }
    catch( signed int ) {}
    catch( int ) {}  // error
}


Compiler Error C2313

'type1' : is caught by reference ('type2') on line number

The specified exception type is handled by a previous handler. The type for the second catch is a reference to the type of the first.

The following is an example of this error:

#include <eh.h>
class C;
void main()
{
    try
    {
        throw "ooops!";
    }
    catch( C& ) {}
    catch( C ) {}   // error
}


Compiler Error C2315

'type1' : reference is caught by 'type2' on line number

The specified exception type is handled by a previous handler. The reference for the second catch has the type of the first.


Compiler Error C2316

'identifier' : cannot be caught, there is no access to the destructor

A thrown exception object had a user defined destructor that did not have public access.


Compiler Error C2317

'try' block starting on line 'number' has no catch handlers

A try block must have at least one catch handler.

The following is an example of this error:

#include <eh.h>
void main()
{
    try
    {
        throw "ooops!";
    }
        // error: no catch handler
}


Compiler Error C2318

no try block associated with this catch handler

A catch handler was defined but it was not preceded by a try block.

The following is an example of this error

#include <eh.h>
void main()
{
        // no try block
    catch( int )   // error
    {
        cout << "Integer exception raised.";
    }
}


Compiler Error C2319

'keyword' must be followed by a compound statement. Missing '{'

A try or catch block was not found following the try or catch statement. The block must be enclosed in parentheses.

The following is an example of this error:

#include <eh.h>
class C;
void main()
{
    try
    {
        throw "ooops!";
    }
    catch( C ) ;    // error, missing block
    catch( C ) {}   // OK
}


Compiler Error C2320

expected ':' to follow access specifier 'specifier'

A colon (:) must come directly after the keyword public, protected, or private.


Compiler Error C2321

syntax error: unexpected 'identifier'

A qualified name was encountered in an unexpected place.

The following is an example of this error:

struct A { struct B { }; };

void f()      // note missing '{'
A::B x;      // error
}


Compiler Error C2322

'identifier' : address of dllimport 'dllimport' is not static

A nonstatic value was given as the address of a function declared with the dllimport modifier.


Compiler Error C2323

compiler limit: out of local keys compiling function 'function'

The specified function declares too many local variables to be compiled. Divide the function into two or more functions.


Compiler Error C2324

'identifier' : unexpected to the right of 'name'

An attempt was made to call a destructor using an incorrect identifier.

The following is an example of this error:

class A {};
typedef A* pA_t;
int i;

void f()
{
    pA_t *ppa = new pA_t;
    ppa->~i;              // error
}


Compiler Error C2325

'type' : unexpected type to the right of 'name'

An attempt was made to call a destructor of an incorrect type.

The following is an example of this error, plus an example of how to avoid the error:

class A {};
void f()
{
    A** ppa = new A *;
    ppa->~A*;          // error
}

typedef A* pA_t;
void g()
{
    pA_t *ppa = new pA_t;
    ppa->~pA_t();     // ok
}


Compiler Error C2326

'declarator' : function cannot access 'name'

An attempt was made to modify a member variable (typically from a friend function) without specifying an object.

The following is an example of this error:

class X
{
    int a;
    friend void f(X *p) { a = 10; } // error
};


Compiler Error C2327

'symbol' : member from enclosing class is not a type name, static, or an enumerator

From within a nested class, you attempted to access a member of the enclosing class that was not a type name, a static member, or an enumerator.

The following is an example of this error:

int x;
class enclose
{
public:
   int x;
   static int s;
   class inner
   {
      void f()
      {
         x = 1;      // error; enclose::x is not static
         s = 1;      // ok; enclose::s is static
         ::x = 1;    // ok; ::x refers to global
      }
   };
};


Compiler Error C2329

'identifier' : __ptr64 not available for pointers to functions

The __ptr64 modifier can only be applied to pointers to data. It cannot be applied to pointers to functions. For example:

typedef void (__ptr64 *pf) (int);   //error

This error only applies to MIPS and DEC ALPHA platforms.


Compiler Error C2332

‘class/struct/union/enum’: missing tag name

You must to specify a variable name for the data type you are declaring.

For example, the following statement generates error C2332:

int struct;


Compiler Error C2333

'function' : error in function declaration; skipping function body

This error will occur only after another error and only for member functions defined inside their class.

The following code in a .cpp file will generate C2333:

struct s1 {
   s1(s1) {
   }
};


Compiler Error C2334

"unexpected token(s) preceding ': or {'; skipping apparent function body"

This error will occur only after another error and only for member functions defined inside their class.

The following code in a .cpp file will generate C2334:

struct s1 {
   s1(s1 func hello) {
   }
};


Compiler Error C2340

'argument' : illegal allocate specifier

Your code includes a __declspec(allocate("<argument>")) statement with an invalid argument. The valid arguments are "_CODE", "_DATA" and "_FAR_DATA".


Compiler Error C2341

section name : segment must be defined using #pragma data_seg or code_seg prior to use

You referred to a section in a #pragma or __declspec(allocate()) statement before defining the section with a #pragma code_seg or #pragma data_seg.

For example, the compiler would generate this error if the following #pragma were placed in a source file to refer to the section "MYSEG" before that section was defined.

#pragma alloc_text (MYSEG, MyLocal)

To fix this, define the section before referring to it. For the above example, you could precede the alloc_text statement with a #pragma code_seg statement to define MYSEG.

#pragma code_seg("MYSEG")
   .
   .
   .
#pragma alloc_text (MYSEG, MyLocal)


Compiler Error C2350

'identifier' is not a static member

A nonstatic member of a class or structure was defined.

Only a static member or a member of an instance or a class or structure can be defined.

The following is an example of this error:

class C
{
public:
   int i;
   static int s;
};
void main()
{
   int C::i = 0;  // error, nonstatic member
   int C::s = 0;  // OK, static member
   C.c;
   c.i = 0;       // OK, member of instance of C
}


Compiler Error C2351

obsolete C++ constructor initialization syntax

A direct base class was not named in the constructor.

The new-style initialization list for a constructor member requires each direct base class to be explicitly named, even if it is the only base class in the list.

The following is an example of this error:

class B
{
public:
   B();
   B( int );
};
class D : public B
{
public:
   D( int i ) : ( i ) {}   // error, B was not named
   D( int i ) : B( i ) {}  // OK
};


Compiler Error C2352

'class::function' : illegal call of non-static member function

The specified nonstatic member function was called in a static member function.

The following is an example of this error:

class X
{
public:
   static void func1();
   void func2();
   static void func3()
   {
   func1();          // OK, calls static func1
   func2();          // error, calls nonstatic func2
   }
};


Compiler Error C2353

'constructor' : improper use of constructor initializers

The constructor initializer syntax was incorrect.

This error can be caused by omitting the constructor definition from a constructor initializer.

The following is an example of this error:

class C
{
public:
   C() : i( 10 );   // error, missing definition
   C() : i( 10 ){}; // OK
private:
   int i;
};


Compiler Error C2354

'reference' : initialization of reference member requires a temporary variable

A reference to a member was initialized in a constructor.

The member should be initialized instead of its reference.


Compiler Error C2355

'this' : can only be referenced inside non-static member functions

The this pointer is only valid within nonstatic member functions. Make sure that the this pointer is being used in this context.

The following code generates this error in global scope:

char *p = this;     // error


Compiler Error C2356

initialization segment must not change during translation unit

The #pragma init_seg statement cannot be preceded by segment initialization code. The #pragma init_seg statement must precede any code and cannot be preceded by another #pragma init_seg statement.

Move the segment initialization code to the beginning of the module. If multiple areas must be initialized, move them to separate modules.


Compiler Error C2357

'identifier' : must be a function of type 'type'

You have declared a version of the atexit function that does not match the version declared internally by the compiler. The function atexit must be declared as follows:

int __cdecl atexit(void (__cdecl *)());


Compiler Error C2360

initialization of 'identifier' is skipped by 'case' label

The specified identifier initialization can be skipped in a switch statement.

It is illegal to jump past a declaration with an initializer unless the declaration is enclosed in a block.

The scope of the initialized variable lasts until the end of the switch statement unless it is declared in an enclosed block within the switch statement.

The following is an example of this error:

void func( void )
{
   int x;
   switch ( x )
   {
   case 0 :
      int i = 1;       // error, skipped by case 1
      { int j = 1; }   // OK, initialized in enclosing block
   case 1 :
      int k = 1;       // OK, initialization not skipped
   }
}


Compiler Error C2361

initialization of 'identifier' is skipped by 'default' label

The specified identifier initialization can be skipped in a switch statement.

It is illegal to jump past a declaration with an initializer unless the declaration is enclosed in a block.

The scope of the initialized variable lasts until the end of the switch statement unless it is declared in an enclosed block within the switch statement.

The following is an example of this error:

void func( void )
{
   int x;
   switch (x)
   {
   case 0 :
      int i = 1;       // error, skipped by default
      { int j = 1; }   // OK, initialized in enclosing block
   default :
      int k = 1;       // OK, initialization not skipped
   }
}


Compiler Error C2362

initialization of 'identifierr' is skipped by 'goto label'

A jump to the specified label prevented the specified identifier from being initialized.

It is illegal to jump past a declaration with an initializer unless:

  • The declaration is enclosed in a block that is not entered.

  • The jump is from a point where the variable has already been initialized.

The following is an example of this error:

void func()
{
   goto label1;
   int i = 1;         // error, initialization skipped
   {
      int j = 1;      // OK, this block is never entered
   }
label1:;
}


Compiler Error C2364

cannot initialize pointer to code-based object 'identifier'

You're trying to statically initialize a pointer to a code-based object. Pointers to code-based objects must be dynamically initialized.

Here's an example of the type of statements that can cause this problem:

__declspec(allocate("_CODE")) int i ;
int *p = &i ;

To fix this, rewrite the statements to dynamically initialize the problem pointer. The above example could be fixed thus:

__declspec(allocate("_CODE")) int i ;
int *p ;
main() {
   p = &i ;
   .
   .
   .
}


Compiler Error C2365

cannot initialize pointer at odd offset

An assignment statement is trying to assign a pointer to an address at an odd offset. Assignments can assign only even-offset addresses to pointer variables.

To fix this, ensure that pointer variables are assigned even offset addresses when dealing with addresses on forced alignments.

As an example of how this condition might arise, consider the following statements:

int i;
#pragma pack(1)
struct
{
   char c;
   int *p;
} s = {'a', &i};

The structure member p lies on an odd offset address, which is then assigned the address value for i.


Compiler Error C2367

'symbol' : redefinition; different uuid specified

The object is multiply declared with a different GUID each time. For example:

struct __declspec(uuid("{00000000-0000-0000-C000-000000000046}")) IUnknown;
struct __declspec(uuid("{00000000-0000-0000-C000-000000000047}")) IUnknown{};


Compiler Error C2368

'identifier' : redefinition; different allocation specifiers

The declaration and definition of the symbol specified different attributes with the __declspec keyword.

The declaration and definition must specify the same attribute.


Compiler Error C2369

'identifier' : redefinition; different subscripts

The given array was already declared with a different subscript.

The following is an example of this error:

int a[10];
int a[20];  // error


Compiler Error C2370

'identifier' : redefinition; different storage class

The given identifier was already declared with a different storage-class specifier.

The following is an example of this error:

extern int i;
static int i;  // error


Compiler Error C2371

'identifier' : redefinition; different basic types

The specified identifier was already declared.

The following is an example of this error:

void main(void)
{
    int i;
    float i;    // error, redefinition
}


Compiler Error C2372

'identifier' : redefinition; different types of indirection

The given identifier was already defined with a different derived type.

The following is an example of this error:

extern int *fp;
extern int fp[];  // error


Compiler Error C2373

'identifier' : redefinition; different type modifiers

The specified identifier was already defined with a different type modifier.

The following is an example of this error:

void __pascal func( void );
void __cdecl func( void );  // error


Compiler Error C2374

'identifier' : redefinition; multiple initialization

The specified identifier was initialized more than once.

A variable can be initialized only once.

The following is an example of this error:

int i = 0;
int i = 1;  // error


Compiler Error C2375

'function' : redefinition; different linkage

The specified function was already declared with a different linkage specifier.

The following is an example of this error:

extern void func( void );
static void func( void );  // error


Compiler Error C2376

'function' : redefinition; different based allocation

The specified function was already declared with a different based allocation.

The following is an example of this error:

int func();
int _based(_segname("S1")) func();
int _based(_segname("S2")) func();  // error


Compiler Error C2377

'identifier' : redefinition; typedef cannot be overloaded with any other symbol

The specified typedef identifier was redefined.

The following is an example of this error:

typedef int i;
int i;  // error


Compiler Error C2378

'identifier' : redefinition; symbol cannot be overloaded with a typedef

The specified identifier was redefined as a typedef.

The following is an example of this error:

int i;
typedef int i;  //error


Compiler Error C2379

formal parameter number has different type when promoted

The type of the specified parameter is not compatible through default promotions with the type found in a previous declaration.

For functions are compatible only if the types of each parameter are compatible after the application of default argument promotions.

This is an error in ANSI C (/Za) and a warning when the Microsoft extension (/Ze) is used.

The following example causes this error:

void func();
void func(char);     // error, char promotes to int


Compiler Error C2380

type(s) preceding 'identifier' (constructor with return type, or illegal redefinition of current class-name?)

The specified constructor returned a value or redefined the class name.

A constructor cannot specify a return value.

This error can be caused by redefining a class name.

The following is an example of this error:

class C
{
public:
   int C();  // error, specifies an int return
   int C;    // error, redefinition of i
   C();      // OK
};


Compiler Error C2385

'class::member' is ambiguous

The specified member was derived from more than one object.

This error is caused by referencing a member of an object that was inherited from more than one object. Make the member unambiguous by providing a cast or by changing the name of the offending members of the base classes.

Warning C4385 is generated in conjunction with this error and provides additional information about the ambiguity.

The following is an example of this error:

struct A { int x; };
struct B { int x; };
struct C : A, B {};
void func ()
{
   C aC;
   aC.x = 9;        // error
}


Compiler Error C2386

ambiguous conversion from 'type1*' to 'type2*'

There was more than one way to make the specified conversion.

Provide an explicit type conversion or change the organization of classes so that the conversion is no longer ambiguous.

Warning C4386 is generated in conjunction with this error and provides additional information about the ambiguity.

The following is an example of this error:

struct A {};
struct B : A {};
struct C : A {};
struct D : B, C {};
void bup ()
{
   D *pD;
   A *pA;
   pA = pD;            // error
}


Compiler Error C2387

ambiguous conversion from 'type1&' to 'type2&'

There was more than one way to make the specified conversion.

Provide an explicit type conversion or change the organization of classes so that the conversion is no longer ambiguous.


Compiler Error C2390

'identifier' : incorrect storage class 'specifier'

The storage class was not legal for the specified identifier with global scope.

The default storage class for this context was used in place of the illegal class.

Correct use of storage classes includes:

  • If the identifier is a function, declaring it with extern storage.

  • If the identifier is a formal parameter or local variable, declaring it with auto storage.

  • If the identifier is a global variable, declaring it with no storage class (that is, auto storage).

The following is an example of this error:

register int i;        //error
void main ()
{
   register int j;     //OK
}


Compiler Error C2391

'identifier' : 'friend' cannot be used during type definition

A complete class declaration was given in a friend declaration.

A friend declaration can specify a member function or an elaborated type specifier, but not a complete class declaration.

The following is an example of this error:

class D { void func( int ); };

class A {
   friend class B { int i; };   // error
   friend class C;              // OK
   friend void D::func(int);    // OK
};


Compiler Error C2398

'name' is not yet implemented

This message is not used.


Compiler Errors C2400 Through C2498

The following topics cover compiler errors C2400 through C2498.


Compiler Error C2400

inline assembler syntax error in 'context'; found 'token'

The given token caused a syntax error within the given context.

Specifying a Pentium instruction can cause this error. Choosing the Pentium option (/G5) causes the compiler to generate instruction sequences optimized for the Pentium, but does not allow instructions specific to the Pentium.


Compiler Error C2401

'identifier' : register must be base in 'context'

The register used within an indirect memory operand must be a base register in this context.


Compiler Error C2402

'identifier' : register must be index in 'context'

The register used within an indirect memory operand must be an index register in this context.


Compiler Error C2403

'identifier' : register must be base/index in 'context'

The register used within an indirect memory operand must be either a base or index register in this context.


Compiler Error C2404

'identifier' : illegal register in 'context'

This register in this context is illegal.


Compiler Error C2405

illegal short forward reference with offset

Short forward references must refer only to a label. An additional offset cannot be used.


Compiler Error C2406

'identifier' : name undefined in 'context'

The identifier used with the SIZE or LENGTH operator or as a specifier with the member-selection operator (.) was not defined.


Compiler Error C2407

illegal 'float' register in 'context'

An NDP register was specified in an illegal context.


Compiler Error C2408

illegal type on PTR operator in 'context'

The first parameter of the PTR operator was not a legal type specification.


Compiler Error C2409

illegal type used as operator in 'context'

An illegal type was used within the given context as an operator.


Compiler Error C2410

'identifier' : ambiguous member name in 'context'

The given identifier within the given context is a member of more than one structure or union.

Use a structure or union specifier on the operand that caused the error. A structure or union specifier is an identifier of type struct or union, either a typedef name or a variable of the same type as the structure or union being referenced. The specifier token must be the left operand of the first member-selection operator (.) to use the operand.


Compiler Error C2411

'identifier' : illegal struct/union member in 'context'

Either the given identifier used with this context is not a member of a visible structure or union or the identifier is not a member of the structure or union specified with the member selection operator (.).


Compiler Error C2412

'identifier' : case-insensitive label redefined

The given label was defined more than once within the current function. Change the spelling of the label and its references.


Compiler Error C2413

'token' : illegal align size

The alignment size used with the ALIGN directive was either missing or outside the valid range.


Compiler Error C2414

illegal number of operands

The opcode does not support the number of operands used.

Check an assembly-language reference manual to determine the correct number of operands for this instruction.

It is possible that the instruction is supported with a different number of operands on a newer processor. The problem can be solved by compiling with the /G1 or /G2 option, but then only machines with the newer processor will be able to execute the extended instruction.


Compiler Error C2415

improper operand type

The opcode does not use operands of this type.

Check an assembly-language reference manual to determine the correct types of operands for this instruction.

It is possible that the instruction is supported with additional operand types on a newer processor. The problem can be solved by compiling with the /G1 or /G2 option, but then only machines with the newer processor will be able to execute the extended instruction.


Compiler Error C2416

'identifier' : illegal opcode for processor

The specified opcode is not valid in this context.

This error can be caused by using an instruction that is legal on a later processor but not on the current processor. In this case the problem can be solved by specifying a processor using, for example, the /G3, /G4, or /G5 options.

This error can also be caused by using an opcode that is valid for the processor but that is not handled by the compiler.


Compiler Error C2417

divide by zero in 'context'

The second parameter to the division operator (/) used within the given context is zero.


Compiler Error C2418

cannot delete browser file: filename

The compiler could not delete the browser file filename. Check whether it is read-only or whether another process is accessing it.


Compiler Error C2419

mod by zero in 'context'

The second parameter to the MOD operator used within the given context is zero.


Compiler Error C2420

'identifier' : illegal symbol in context

The given identifier is illegal within the given context.


Compiler Error C2421

PTR operator used with register in 'context'

The PTR operator must not be used with a register operand.


Compiler Error C2422

illegal segment override in 'operand'

Within inline assembler code, a segment override operator (':') was used improperly on an operand.

The register preceding the segment override operator must be a segment register, and the only segment register in the operand. The segment override operator cannot appear within the brackets of the indirection operator ('[' and ']') and the expression following the segment override operator must be either an immediate operand or a memory operand; it cannot be a register operand.

The following is an example of this error:

_asm
{
  mov    AX, [BX:ES]        //Error
  mov    AX, ES:[BX]        //OK
}


Compiler Error C2423

'number' : illegal scale

The number used to scale a register in an inline assembler routine was illegal.

Registers can be scaled only by 1, 2, 4, or 8.

The following code generates this error:

_asm
{
  lea    EAX, [EAX*3]            //Error
  lea    EAX, [EAX+EAX*2]        //OK
}


Compiler Error C2424

'token' : improper expression in 'context'

The given token was used to form an improper expression within the given context.


Compiler Error C2425

'token' : non-constant expression in 'context'

The given token was used to form a nonconstant expression within the given context.


Compiler Error C2426

'token' : illegal operator in 'context'

The given token must not be used as an operator within the given context. For example, index operators cannot be nested.


Compiler Error C2427

'identifier' : jump referencing label is out of range

A branch to the specified label contains code that cannot be jumped over.

The following example causes this error:

        jz label1
        inc EAX

label1: inc ECX

In this example, you can correct the error by either removing excess code between the branch and the label or inverting the jump:

        jnz label2
        jmp label1
label2: inc EAX

label1: inc ECX


Compiler Error C2428

'operation' : not allowed on operand of type 'bool'

The pre-decrement and post-decrement operators (--) cannot be applied to objects of type bool. For example:

void g(bool fFlag) {
   --fFlag;   //Error
   fFlag--;   //Error
}


Compiler Error C2429

'label' : illegal far label reference

FAR PTR cannot be used on jumps or calls to labels. Far references to functions are allowed only if the function has been declared.


Compiler Error C2430

more than one index register in 'identifier'

More than one of the specified registers were scaled.

The 32-bit targeted compiler supports scaled indexing, but you can only scale one register.

The following is an example of this error:

_asm mov eax, [ebx*2+ecx*4]


Compiler Error C2431

illegal index register in 'identifier'

The ESP register was scaled or used as both the index and base register.

The SIB encoding for the 80386 processor does not allow scaling by ESP or using ESP as both the index and base register.

The following examples cause this error:

_asm mov ax, [ESI+2*ESP]
_asm mov ax, [esp+esp]


Compiler Error C2432

illegal reference to 16-bit data in 'identifier'

A 16-bit register was used as an index or base register.

The 32-bit targeted compiler does not support referencing 16-bit data, which is supported by the chip using the address size prefix. This means that 16-bit registers cannot be used as index or base registers if you are compiling for 32-bit code.

The following is an example of this error:

_asm mov eax, DWORD PTR [bx]


Compiler Error C2433

'identifier' : 'modifier' not permitted on data declarations

The specified modifier was used for a data declaration.

The friend, virtual, and inline modifiers cannot be used for data declarations.


Compiler Error C2434

'identifier' : cannot convert default argument from 'type1' to 'type2'

The indicated default parameter could not be converted into the type specified in the function's formal parameter list. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

This error can be caused by an incorrect function prototype or by using the wrong value for a default parameter. To use the indicated default parameter, you should define a conversion operator or a constructor that takes a single parameter of the same type as the specified default parameter.

The following is an example of this error. Note that if the conversion operator in A is supplied, then there is no error.

class A
{
public:
   int i;
} a;
class B
{
public:
   operator int() { return i; }    // conversion operator
   int i;
} b;
void func1( int j = a ) {}  // error, can't convert a to int
void func2( int j = b ) {}  // OK


Compiler Error C2435

'identifier' : function called before default arguments were resolved

The specified function was declared or defined with default arguments, but was called before the default arguments were defined.

The following is an example of this error:

class C
{
public:
   void a(void)
   {
      b();                   // error caught here
   }
   void b(void* ptr = sp);   // move this line above the definition
   static void *sp;          // a() to avoid error
};


Compiler Error C2436

'identifier' : member function or nested class in constructor initializer list

Cannot initialize member functions or local classes in the constructor initializer list. For example:

struct S{
   int f();
   struct Inner{
      int I;
   };
   S():f(10), Inner(0){}   //Error
};


Compiler Error C2437

'identifier' : already initialized

The specified identifier was already initialized.

An object can be declared more than once but can be initialized only once.


Compiler Error C2438

'identifier' : cannot initialize static class data via constructor

A constructor was used to initialize a static member of a class.

Static members should be initialized in a definition outside the class declaration.

The following example shows how static members are initialized:

class X
{
public:
   static const int i;
   static int j;
};
const int X::i = 1;
int X::j = 2;


Compiler Error C2439

'identifier' : member could not be initialized

The indicated class, structure, or union member could not be initialized.

This error can be caused by trying to initialize an indirect base class or structure or an inherited member of a class or structure. An inherited member should be initialized by the constructor of the class or structure.


Compiler Error C2440

'conversion' : cannot convert from 'type1' to 'type2'

The compiler was unable to cast from ‘type1’ to ‘type2.’ If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The following example illustrates this error.

void main()
{

   int *i;
   float j;

   j = (float)i; /* cannot cast from
              pointer to int to float */

}


Compiler Error C2441

function call through pointer before default arguments were resolved

A function was declared or defined with default arguments, but was called before the default arguments were defined.

The following is an example of this error:

class C
{
public:
   void a(void)
   {
      (*c)();                   // error caught here
   }
   void (*c)(void*ptr = sp);    // move this line above the definition of
   static void *sp;             // a() to avoid error
};


Compiler Error C2443

operand size conflict

The instruction required operands of the same size.

One of the operands must be changed so that both operands have the same size.

The following is an example of this error:

short var;
void main()
{
   __asm xchg ax,bl            // error
   __asm mov al,red            // error
   __asm mov al,BYTE PTR var   // OK
}


Compiler Error C2444

'identifier' : used ANSI prototype, found 'type', expected '{' or ';'

The specified function prototype was followed by a type.

This error can be caused by a missing semicolon.


Compiler Error C2446

'operator' : no conversion from 'type1' to 'type2'

The compiler is unable to convert type1 to type2. Normally the compiler is able to convert from one type to another, but sometimes a conversion does not make sense because it would violate the semantics of C or C++. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The example below illustrates two conversion problems:

  1. Converting an int to a pointer to char has no meaning and is not allowed.

  2. Converting a pointer to a const object to a pointer to a non-const object is not allowed. If you could obtain such a pointer, you could modify the const object through it, violating the sematics of const.
    int i;
char *p;
int *j;
const int *cj;

void main()
{
   p = i;  // ERROR #1: conversion has no meaning
   j = cj; // ERROR #2: pointer to const obj
}


Compiler Error C2447

missing function header (old-style formal list?)

An open curly brace ({) was found at global scope without a corresponding function header.

This error can be caused by using the old-style C-language formal list.

Check that the function being defined has an appropriate function declaration.

The following is an example of this error:

int c;
{}       // error


Compiler Error C2448

'identifier' : function-style initializer appears to be a function definition

The specified function definition was incorrect.

This error can be caused by using the old-style C-language formal list.

The following is an example of this error:

void func(c)
   int c;
{}             // error


Compiler Error C2449

found '{' at file scope (missing function header?)

An opening curly brace ({) was found at file scope.

This error is probably caused by adding a semicolon between a function header and the opening curly brace of the function definition.

The following is an example of this error:

int __pascal func(void);  // extra semicolon on this line
{                         // error detected here


Compiler Error C2450

switch expression of type 'type' is illegal

The specified switch expression evaluated to an illegal type.

A switch expression must evaluate to an integral type or a class type that has an unambiguous conversion to an integral type.

If the expression evaluates to a user-defined type, a conversion operator needs to be supplied.

The following is an example of this error:

class X
{
public:
   int i;
} x;
class Y
{
public:
   int i;
   operator int() { return i; }  // conversion operator
} y;
void main()
{
   int j = 1;
   switch ( x )              // error, x is not type int
   {
 default:  ;
   }
   switch ( y )              // OK
   {
 default:  ;
   }
}


Compiler Error C2451

conditional expression of type 'type' is illegal

The conditional expression evaluated to an illegal type.


Compiler Error C2452

array bound expression of type 'type' is illegal

An array was declared with a bound expression that could not be converted to type int.

The following is an example of this error:

class C { int a; } aC;
class D { public: int a; operator int() { return a; } } aD;
class E { public: double a; operator double() { return a; } } aE;
int (*pf)();

void func()
{
   char *buf;
   int *pi;

   buf = new char[aC];  // error, no conversion from C to int
   buf = new char[pi];  // error, int * is illegal type for array bound
   buf = new char[pf];  // error, int (*)() is illegal for array bound
   buf = new char[10L]; // OK
   buf = new char[aD];  // OK, conversion by D::operator int()
   buf = new char[aE];  // OK, conversion by E::operator double()
}


Compiler Error C2453

array bound expression uses function name

An array was declared with a bound expression that was a function name.

An array bound must be a type that has a conversion to type int.

The following is an example of this error:

int func();

void bunc()
{
    char *buf;

    buf = new char[10];     // OK
    buf = new char[func];   // error, array bound is function name
    buf = new char[bunc];   // error
}


Compiler Error C2454

improper operand type for processor

The specified operand is not valid for the target processor.


Compiler Error C2455

improper operand type in instruction

The instruction contained an invalid operand type.


Compiler Error C2456

illegal opcode for processor

The specified opcode is not valid for the target processor.


Compiler Error C2458

'identifier' : redefinition within definition

The specified class, structure, union, or enumeration was redefined in its own declaration.

The following is an example of this error:

class C
{
    enum i { C };   // error
};


Compiler Error C2459

'identifier' : is being defined; cannot add as an anonymous member

The specified class, structure, or union was redefined in its own scope by a member of an anonymous union.

The following is an example of this error:

class C
{
    union { int C; };   // error
};


Compiler Error C2460

'identifier1' : uses 'identifier2', which is being defined

The given class or structure (identifier2) was declared as a member of itself (identifier1).

Recursive definitions of classes and structures are not allowed.

The following is an example of this error:

class C
{
   C aC;    // error
};


Compiler Error C2461

'class' : constructor syntax missing formal parameters

The constructor for the given class did not specify any formal parameters. The declaration of a constructor must specify a formal parameter list in parentheses. This list can be null.

Add a pair of parentheses after the class::class identifier.

The following is an example of this error:

class C
{
    C::C;        // error
    C::C();      // OK
};


Compiler Error C2462

'identifier' : cannot define a type in a 'new-expression'

A type cannot be defined in the operand field of the new operator.

Put the type definition in a separate statement.

The following is an example of this error:

void main()
{
    new struct S { int i; };     // error
}


Compiler Error C2463

cannot define an anonymous type in a 'new-expression'

An anonymous type cannot be defined in the operand field of the new operator.

Create a named type definition in a separate statement, then use the new operator.

The following is an example of this error:

void main()
{
    new struct { int x; };  // error
}


Compiler Error C2464

'identifier' : cannot use 'new' to allocate a reference

The specified reference identifier was allocated with the new operator.

Since references are not memory objects, the new operator cannot return a pointer to them.

Use the standard variable declaration syntax to declare a reference.

The following is an example of this error:

void main()
{
    new ( int& ir );   // error
}


Compiler Error C2465

cannot define an anonymous type inside parentheses

An anonymous structure, union, or enumerated type was defined inside a parenthetical expression.

This is illegal in C++ programs, as the definition is meaningless in function scope.


Compiler Error C2466

cannot allocate an array of constant size 0

An array of constant size 0 was allocated or declared.

The constant expression used to allocate or declare an array must be an integral type greater than zero.

An array declaration with a zero subscript is legal only for a class, structure, or union member, and when the Microsoft extensions (/Ze) are enabled.

The following examples cause this error:

int *p = new X[0];        // error
C *aC = new [int_var] C;  // error
int[0]                    // error


Compiler Error C2467

illegal declaration of anonymous 'user-defined-type'

A nested user defined type was declared. This is an error when the ANSI compatibility option (/Za) has been enabled.

The following is an example of this error:

int main()
{
   struct X
   {
      union { int i; };  // error, nested declaration
   };
   return 0;
}


Compiler Error C2468

'new' : cannot allocate 'const'/'volatile' objects (type is 'type')

The new operator was used to create an object of the specified type that was declared as const or volatile.

The following is an example of this error:

void main(void)
{
   new int * const;       // error
   new int * volatile;    // error
}


Compiler Error C2469

‘operator’: cannot allocate ‘type’ object

You could reproduce this error with the following code example:

int *i = new void;


Compiler Error C2471

cannot update program database 'file'

The specified database could not be written to.

Possible causes of this error include:

  • Insufficient disk space.

  • Attempting to write to a read-only volume.

  • A sharing violation.


Compiler Error C2479

'identifier' : 'allocate( )' is only valid for data items of static extent

The __declspec( allocate()) syntax can only be used for nonstatic objects.


Compiler Error C2480

'identifier' : 'thread' is only valid for data items of static extent

An automatic variable, nonstatic data member of a class, or a function parameter cannot be declared with the thread attribute.

A global variable, a static data member variable or a local static variable can be declared with the thread attribute.


Compiler Error C2481

'identifier1' : cannot be initialized using address of 'thread' variable 'identifier2'

The address of variable identifier2 is not static; rather, it is a dynamic value which can only be determined in the context of a particular thread. A static expression must be used to initialize identifier1.


Compiler Error C2482

'identifier' : dynamic initialization of 'thread' data not allowed

Variables that are declared with the thread attribute cannot be initialized with an expression that requires evaluation at run-time. A static expression must be used to initialize thread data.


Compiler Error C2483

'identifier' : object with constructor cannot be declared 'thread'

Variables that are declared with the thread attribute cannot be initialized with an expression that requires evaluation at run-time, such as a constructor. A static expression must be used to initialize thread data.


Compiler Error C2484

'identifier' : attribute 'attribute' doesn't match previous declaration

The specified identifier was already declared with a different attribute.


Compiler Error C2485

'identifier' : unrecognized extended attribute

The specified declaration attribute is not valid.


Compiler Error C2486

'__LOCAL_SIZE' only allowed in function with the 'naked' attribute

In inline assembly functions, the name __LOCAL_SIZE is reserved for functions declared with the naked attribute.


Compiler Error C2487

'identifier' : member of dll interface class may not be declared with dll interface

You can declare a whole class with DLL interface, or certain members of a non-DLL interface class. However, you cannot declare a class with DLL interface and then declare a member of that class with DLL interface.


Compiler Error C2488

'identifier' : 'naked' can only be applied to function definitions

The naked attribute was applied to a function declaration.

The following is an example of this error:

__declspec( naked )  int func();  // error, declaration, not definition
__declspec( naked ) int i;        // error, i is not a function


Compiler Error C2489

'identifier' : initialized auto or register variable not allowed at function scope in 'naked' function

The following is an example of this error:

__declspec( naked ) int func()
{
   int i = 1;            // error
   register int j = 1;   // error
}


Compiler Error C2490

'keyword' not allowed in function with 'naked' attribute

A function defined as naked cannot use structured exception handling.

The following is an example of this error:

__declspec( naked ) int func()
{
   __try{}     // error, structured exception handling
}


Compiler Error C2491

'identifier' : definition of dllimport identifier not allowed

Data, static data members, or functions can be declared as dllimports, but not defined as dllimports.


Compiler Error C2492

'identifier' : 'thread' data may not have dll interface

The specified variable was declared with the thread attribute and with DLL interface. However, the address of the thread variable cannot be known before run-time so it cannot be linked to a DLL import or export.


Compiler Error C2493

illegal form of __based

A __based expression must be based on a pointer.

The following is an example of a valid __based expression:

char * mybase;
int __based(mybase) * ptr;


Compiler Error C2494

'keyword' may not appear in termination block

You cannot use 'keyword' inside a __finally block.


Compiler Error C2495

'identifier' : 'nothrow' can only be applied to function declarations or definitions

The nothrow extended attribute can only be applied to function declarations or definitions. For example:

__declspec(nothrow) class X {
   int m_data;
} x;

The above code generates this error.


Compiler Error C2496

'identifier' : 'selectany' can only be applied to statically initialized data items with external linkage

The selectany extended attribute can only be applied to the static initialization of externally visible and global data items. See the following example:

// OK
__declspec(selectany) int x1 = 1;

// error - x2 is not externally visible
const __declspec(selectany) int x2 = 2;

// OK
extern const __declspec(selectany) int x3 = 3;

// error - x4 is not initialized
__declspec(selectany) int x4;
// error - dynamic initialization of x5
__declspec(selectany) int x5 = foo();
// error - x6 is not externally visible
static __declspec(selectany) int x6 = 6;

extern const int x7;
// OK - redeclaration of x7 that is extern
const __declspec(selectany) int x7 = 7;


Compiler Error C2498

'function' 'novtable' can only be applied to class declarations

For example, using __declspec(novtable) with a function, as follows, is illegal:

void __declspec(novtable) f() { }


Compiler Errors C2500 Through C2599

The following topics cover compiler errors C2500 through C2599.


Compiler Error C2500

'identifier1' : 'identifier2' is already a direct base class

The specified class (or structure) appeared more than once in a list of base classes for a derived class.

A class is called a direct base if it is mentioned in the base list. A class is called an indirect base if it is not a direct base but is a base class of one of the classes mentioned in the base list.

A class cannot be specified as a direct base class more than once. A class can be used as an indirect base class more than once.

The following is an example of this error:

class A { };
class B : public A, public A { };    // error
class C : public A { };
class D : public A { };
class E : public C, public D { };    // OK, contains two As


Compiler Error C2501

'identifier' : missing storage-class or type specifiers

The identifier was declared without specifying its type.

Tips

  • The most typical cause of this error is a typographical error. Recheck the identifier to ensure it is spelled correctly and that the alphabetic case is correct.

  • This error may occur when a type specifier is omitted in the declaration of an identifier. In the following example, assume the header file for the class CUndeclared has been omitted:
    class CMyClass {
private:
   CUndeclared m_myClass;  // Error: Class unknown
} ;


Compiler Error C2502

'identifier' : too many access modifiers on the base class

The specified base class had more than one access modifier.

A base class or structure can be declared with only one access modifier (public, private, or protected).

The following is an example of this error:

class A { };
class B { };
class C : private public A { };     // error
class D : private A { };            // OK
class E : public A, private B { };  // OK


Compiler Error C2503

'class' : base classes cannot contain zero-sized arrays

The specified base class (or structure) contained a zero-sized array.

An array in a class must have at least one element.


Compiler Error C2504

'class' : base class undefined

The specified base class was declared but never defined.

This error can be caused by a missing include file or an external base class that was not declared with the extern specifier.

The following is an example of this error:

class A;                 // error, A is undefined
class A {};              // OK, A is defined
class B : public A {};   // the error is detected here


Compiler Error C2505

'identifier' : is not a legal base class

The specified identifier was not a class (or structure) but was used to derive a class.

A class can be derived only from classes. This error can be caused by naming a variable or type in the base class list.

The following is an example of this error:

class B { };
class D : public B { };  // OK, D is derived from B
typedef int I;
class E : public I { };  //  error, I is not a class


Compiler Error C2506

'class::identifier' : ambiguous

The specified name referred to more than one class member.

To access a base class or structure, an expression must refer to one unique function, object, type, or enumerator. The scope resolution operator (::) can be used to resolve the ambiguity.

The check for ambiguity is done before access control. A private base class containing only private members has the same potential for ambiguity as a public class.

The following is an example of this error:

class A
{
public:
   int a;
};
class B
{
private:
   int a;
};
class C : public A, private B { };
C c;
int j = c.a;          // error, could be A::a or B::a
int i = c.A::a;       // OK, resolved ambiguity


Compiler Error C2507

'identifier' : too many virtual modifiers on the base class

The specified class or structure was declared as virtual more than once.

Only one virtual modifier can be used for each base class in a list of base classes.

The following is an example of this error:

class A {};
class B : virtual virtual public A {}; // error
class C : virtual public A {};         // OK


Compiler Error C2508

'identifier' : access denied

The specified nonpublic class member could not be accessed.

A class (or structure or union) member that has been declared with private or protected access can only be accessed by member functions of the class.


Compiler Error C2509

'identifier' : member function not declared in 'class'

The function was not declared in the specified class.

This error can be caused by specifying the wrong class when calling the function.


Compiler Error C2510

'identifier' : left of '::' must be a class/struct/union

The named identifier was not a class, structure, or union.

A class, structure, or union name must appear on the left side of the scope resolution operator (::) if any name is used.


Compiler Error C2511

'identifier' : overloaded member function not found in 'class'

The specified function was not declared for the given parameters. In all the versions of the overloaded function, none of them had the same parameters in the same order as specified in the erroneous function call.

This error can be caused by a mismatch in the parameter list of the specified function.

Tips

  • Ensure that the correct arguments are being passed when calling the function.

  • Make sure the arguments are in the correct order when calling the function.

  • Make sure the argument names are spelled correctly.


Compiler Error C2512

'identifier' : no appropriate default constructor available

No default constructor was available for the specified class, structure, or union.

The compiler will supply a default constructor only if user-defined constructors are not provided. If you provide a constructor that takes a nonvoid parameter, then you must also provide a default constructor. The default constructor can be called with no parameters, that is, a constructor with default values for all parameters.


Compiler Error C2513

'specifier' : no variable declared before '='

The specified type was used in a declaration that did not name an identifier.

The following is an example of this error:

int = 9;  // error


Compiler Error C2514

'class' : class has no constructors

The specified class was initialized with parameters for which no constructor was defined.

Constructors must be declared with parameter lists that match every parameter list used to initialize objects of the class, structure, or union.


Compiler Error C2515

'identifier' : not in class 'class'

The specified identifier was not a member of the given class.


Compiler Error C2516

'name' : is not a legal base class

The specified class was derived from a type name defined by a typedef statement.

The following is an example of this error:

typedef   unsigned long ulong;
class C   : public ulong {}; // error


Compiler Error C2517

'identifier' : right of '::' is undefined

The identifier on the right side of the scope resolution operator (::) was not defined.

The identifier on the right side of the scope resolution operator must be a defined member of the class, structure, or union found on the left side of the operator. If no class, structure, or union is named, then the identifier on the right side of the operator must be declared with global scope.


Compiler Error C2518

keyword 'keyword' illegal in base class list; ignored

A class or structure in a base class list was specified with the class or struct keyword. Only the name of the class or structure should be used.

The following is an example of this error:

class B {};
class C   : public class B {}; // error
class C   : public B {};       // OK


Compiler Error C2519

cannot convert 'type1 *' to 'type2 *'

A pointer to type1 could not be converted to a pointer to type2.

Since type1 was not derived from type2, implicit conversion was not possible.

A pointer to one type generally cannot be implicitly converted to a pointer to another type. Conversion to a void is possible if the size of void is greater than the size of the original pointer.

If a pointer to one type must be converted to a pointer to another type, then explicit conversion should be used.


Compiler Error C2520

conversion from unsigned __int64 to double not implemented, use signed __int64

Click for information on __int64 or data type ranges.


Compiler Error C2521

destructors do not take parameters

You attempted to use a destructor with parameters. Rewrite the statement without parameters.


Compiler Error C2522

'name' : cannot be constructed because it cannot be destroyed in this context

This message is not used.


Compiler Error C2523

'identifier1::~identifier2' : destructor tag mismatch

A destructor for the specified class was declared with a different name.

The destructor for a class must have the same name as the class itself and must be preceded by a tilde (~).

The constructor and destructor are the only members of a class that have the same name as the class.


Compiler Error C2524

'identifier' : destructors must have a 'void' formal parameter list

The specified destructor had a nonvoid formal parameter list.

A destructor can take only a void parameter. Other parameter types are not allowed.


Compiler Error C2525

'identifier' : explicit destructor is named but not called

The specified explicit destructor member selection did not have a function call operator (matched parentheses).

The following is an example of this error:

struct C
{
   ~C();
};

void func( CpC )
{
   pC->~C;       // error
   pC->~C();     // OK
}


Compiler Error C2526

'identifier1' : C linkage function cannot return C++ class 'identifier2'

A function defined with C linkage cannot return a user-defined type.


Compiler Error C2527

'identifier' : array of references must be fully initialized

Elements of the specified array were not initialized.

An initializer must be supplied for every element of an array of references.

The following is an example of this error:

int a, b, c;
int &ai[3];               // error, elements not initialized
int &ai[3] = { a, b, c }; // OK


Compiler Error C2528

'name' : pointer to reference is illegal

A pointer to a reference was declared.

The variable must be dereferenced before a pointer to it can be declared.


Compiler Error C2529

'name' : reference to reference is illegal

A reference to a reference was declared.

This error can be avoided by using pointer syntax and declaring a reference to a pointer.


Compiler Error C2530

'identifier' : references must be initialized

A reference was not initialized when it was declared.

The following cases are the only times a reference can be declared without initialization:

  • It is declared with the keyword extern.

  • It is a member of a class, structure, or union and is initialized in the class's constructor function.

  • It is declared as a parameter in a function declaration or definition.

  • It is declared as the return type of a function.


Compiler Error C2531

'identifier' : reference to a bit field illegal

A reference to the specified bit field was declared.

A reference to a bit field is not allowed.


Compiler Error C2532

'identifier' : illegal modifier for reference

The specified reference was changed.

References cannot be modified to refer to another object.

If the reference must be modified, then it should be implemented as a pointer instead.


Compiler Error C2533

'identifier' : constructors not allowed a return type

The specified constructor was declared with a return type.

A constructor does not return a value and has no return type. A return type of void is not allowed.

The following is an example of this error.

class X
{
public:
   void X( void ) { ... };  // error, return type declared
   X( void ) { ... };       // OK, no return type declared
};


Compiler Error C2534

'identifier' : constructor cannot return a value

The specified constructor cannot return a value.

A constructor cannot return a value of any type, including a return type of void.

This error can be eliminated by removing the return statement from the constructor definition.


Compiler Error C2535

'identifier' : member function already defined or declared

The specified member function was defined or declared earlier.

This error can be caused by repeating the same formal parameter list in more than one function definition or declaration.


Compiler Error C2536

'identifier1::identifier2' : cannot specify explicit initializer for arrays

The specified member of a class, structure, or union could not be initialized.

This error can be caused if a constructor is not available to initialize one or more members of an array. If the size of the array is greater than the number of initializers, then a default constructor must be defined.

Alternatively, this error can be caused by declaring a nonstatic array with the const specifier. This kind of array cannot be explicitly initialized.


Compiler Error C2537

'identifier' : illegal linkage specification

The indicated linkage specifier was not legal.

This error can be caused by using a linkage specifier that is not supported. Only the "C" linkage specifier is supported.

This error can also be caused by overloading more than one function with "C" linkage. Only one of a set of overloaded functions can be declared with "C" linkage.


Compiler Error C2538

new : cannot specify initializer for arrays

An initializer was given for the specified array created with the new operator.

The new operator creates arrays of objects by calling the default constructor for each element of the array. The elements of the array cannot be initialized to distinct values.


Compiler Error C2539

new : 'identifier' : no default constructor to initialize arrays of objects

A default constructor was not available to initialize an array of objects of the specified class, structure, or union.

Initializing an array of objects requires a default constructor. The default constructor is called separately for each object in the array.

This error can be caused by not defining a default constructor. If any constructor is defined, then the compiler will not generate a default constructor. A default constructor (one that can be called with no parameters) must be explicitly defined in this case.


Compiler Error C2540

non-constant expression as array bound

The specified array bound was not a constant expression.

An array must be declared with a constant bound.

The following example shows an illegal way to declare an array:

int i;
int A[i];        // error, i is nonconstant

and legal ways to declare an array:

const j = 20;
int A[j];        // OK, j is constant
int B[32];       // OK, 32 is a literal


Compiler Error C2541

delete : cannot delete objects that are not pointers

The delete operator was used on an object that was not a pointer.

The delete operator can only be used on pointers.

The following is an example of this error:

void main()
{
   int i;
   delete i;            // error, i is not a pointer
   intip = new int;
   delete ip;           // OK
}


Compiler Error C2542

'identifier' : class object has no constructor for initialization

There was no constructor to initialize the specified object.

A constructor with the same parameter list used in the initialization must be supplied.

This error can also be caused by initializing an object with incorrect parameters.


Compiler Error C2543

expected ']' for operator '[]'

The left square bracket of the subscripting operator was missing.

This error can be caused by expansion of a macro.


Compiler Error C2544

expected ')' for operator '()'

The left parenthesis of the function call operator was missing.

This error can be caused by expansion of a macro.


Compiler Error C2545

'identifier' : unable to find overloaded operator

The specified operator could not be used with the provided operands.

An overloaded operator should be supplied with the required operands.

This error can be caused by using the operator with operands of the incorrect type. Defining a conversion operator or a constructor that takes a single parameter may allow the operator to be used.


Compiler Error C2546

'operator' : illegal mix of 'void' pointer with pointer to type

The specified operator was called with incompatible pointer types.

This error can be caused by using an arithmetic operator on a void pointer. Pointer arithmetic can only be done with pointers to objects.

If the operator must be used with a void pointer, then the operator can be overloaded. Alternatively, cast the void pointer into a type that can be used with the specified operator.


Compiler Error C2547

illegal cast of overloaded function

A pointer to a function type was converted to an overloaded type.

Conversion of a pointer to a function into a pointer to an overloaded function is not allowed.

The following is an example of this error:

int func();
int func( int );
( int (*)() )func;      // error, func is overloaded
int func2();
( void (*)() )func2;    // OK, func2 is not overloaded


Compiler Error C2548

'identifier1::identifier2' : missing default parameter for parameter identifier3

A parameter was missing in a default parameter list.

If a default parameter is supplied anywhere in a parameter list, then all subsequent parameters on the right side of the default parameter must also be defined.

The following is an example of this error:

void func( int = 1, int, int = 3);  // error
void func( int, int, int = 3);      // OK
void func( int, int = 2, int = 3);  // OK


Compiler Error C2549

user-defined conversion cannot specify a return type

A user-defined conversion cannot specify a return type.

The following is an example of this error:

class X
{
public:
   int operator int() { return value; }   // error
   operator int() { return value; }       // OK
private:
   int value;
};


Compiler Error C2550

'identifier' : constructor initializer lists are only allowed on constructor definitions

A base class initializer list was used on a function definition that was not a constructor.

The following is an example of this error:

class C
{
public:
   C();
};

class D : public C
{
public:
   D();
   void func();
};

void D::func() : C() {}  // error
D::D() : C() {}          // OK


Compiler Error C2551

'void *' type needs explicit cast

A void pointer was assigned to a nonvoid pointer by implicit conversion.

An explicit cast is necessary to convert a void pointer to a nonvoid pointer.


Compiler Error C2552

'identifier' : non-aggregates cannot be initialized with initializer list

The specified identifier was incorrectly initialized.

An initializer list is needed to initialize the following types:

  • An array

  • A class, structure, or union that does not have constructors, private or protected members, base classes, or virtual functions

These types are known as “aggregates.”


Compiler Error C2553

no legal conversion of return value to return type 'type'

The return value could not be converted to the required type. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

You may need to supply a user-defined conversion operator to cast the return value.


Compiler Error C2554

'name' : __based is illegal on references to functions

This message is not used.


Compiler Error C2555

'class1::function1' : overriding virtual function differs from 'class2::function2' only by return type or calling convention

The specified virtual function and a derived overriding function had identical parameter lists but different return types.

An overriding function in a derived class cannot be redefined to differ only by its return type from a virtual function in a base class.

A function in a derived class or structure overrides a virtual function in a base class only if their names, parameters, and return values are all identical. (If the functions have different parameters, the compiler treats them as different functions and does not override the virtual function.)

It may be necessary to cast the return value after the virtual function has been called.

The following is an example of this error:

struct X
{
   virtual void func();
};
struct Y : X
{
   char func();  // error
};


Compiler Error C2556

'identifier' : overloaded functions only differ by return type

The indicated overloaded functions had different return types but the same parameter list.

Each overloaded function must have a distinctly different formal parameter list.


Compiler Error C2557

'identifier' : private and protected members cannot be initialized without a constructor

Private and protected members cannot be assigned a value except by the class's member or friend functions. Nonpublic members should be initialized in the class constructor.


Compiler Error C2558

'identifier' : no copy constructor available

No copy constructor was defined to copy the specified class.

A copy constructor is used to initialize an object with the values of another object of the same type — that is, to make a copy of the object.

If no copy constructor is provided, the compiler will generate a default copy constructor. A default copy constructor is not generated by the compiler if any user-defined copy constructor has been defined.

This error can occur if a private copy constructor is declared. In most cases, a class with a private copy constructor should not be copied.

Declaring a private copy constructor is a common C++ programming technique used to prevent the direct use of certain classes. For instance, a class may be useless by itself or require another class in order to work properly. In this case, you can prevent direct use of a class by declaring the copy constructor to be private.

Tips

  • There may be a case when the class causing the error has a private copy constructor but you have determined it is safe to use this class by itself. In this instance, you can derive a new class from the class causing the error and make a public or protected copy constructor available in the new class. Use this new derived class in place of the original.

  • For more information, see Compiler Errors when Implementing a CObject-Derived Class.


Compiler Error C2559

'identifier' : no match for specified operator

There was an attempt to use the new operator to call the constructor for the given identifier, but there was no constructor that corresponded to the given ambient memory model or distance.

Make sure that the appropriate constructors have been defined for each memory model or distance being used.


Compiler Error C2560

'function' : overloaded function differs only by calling convention/memory model

The specified overloaded function declarations did not specify different formal parameter types. Overloaded functions cannot differ only by calling convention or memory model.

The following is an example of this error:

void _cdecl  func();
void _pascal func();       // error
void _pascal func( int );  // OK


Compiler Error C2561

'identifier' : function must return a value

The specified function was declared as returning a value, but the function definition did not contain a return statement.

This error can be caused by an incorrect function prototype.

Tips

  • If the function does not return a value, the function should be declared with a void return type.

  • Make sure that all possible branches of the function return a value of the type declared in the prototype.

  • C++ functions containing inline assembly routines that store the return value in the AX register may need a return statement added to the function. Copy the value in AX to a temporary variable and return that variable from the function.


Compiler Error C2562

'identifier' : 'void' function returning a value

The indicated function was declared as a void function but returned a value.

This error can be caused by an incorrect function prototype. If the function returns a value, the return type must be specified in the function declaration.


Compiler Error C2563

mismatch in formal parameter list

The formal parameter list of a function or pointer to a function did not match those of another function or pointer to a member function, respectively.

The assignment of the functions or pointers could not be made because of incompatible declarations.

The following is an example of this error:

void func( int );
void func( int, int );
main()
{
   void *fp();
   fp = func;                // error
   fp = func( int, int );    // OK
}


Compiler Error C2564

'type' : function-style conversion to builtin type takes only one argument

A function-style type cast of a built-in type can only take one argument. The error is generated when multiple arguments are supplied. For example:

void g(float f, double d) {
   int j=int(f, d);   //error
}


Compiler Error C2565

'::identifier' was previously declared as a global function

The indicated member function had the same name as a function declared earlier with global scope.


Compiler Error C2566

overloaded function in conditional expression

The overloaded function in a conditional expression could not be evaluated.

The following is an example of this error:

int f( int );
int f( double );
void main()
{
   if( f );      // error, which f?
   if( f(1) );   // OK
}


Compiler Error C2567

'identifier' : intrinsic function must have prototype when using C++

The specified intrinsic function was not prototyped.

The following is an example of this error:

#include <string.h>
#pragma intrinsic( abs )     // error, no prototype for abs()
#pragma intrinsic( strcpy )  // OK, prototyped in string.h


Compiler Error C2568

'identifier1' : unable to resolve function overload

The compiler could not unambiguously determine which overloaded function to call.

The actual parameters passed to the function should be cast to match the formal parameters listed in the declaration of one of the specified functions. One parameter match must be better than any of the other possible matches.


Compiler Error C2569

'identifier' : enum/union cannot be used as a base class

A class was derived from the specified union or enum.

A union or enum is not allowed to be a base class. If another user-defined type must be derived from the specified union/enum, the union/enum should be changed to a class or structure.


Compiler Error C2570

'identifier' : union cannot have base classes

A union was derived from a class, structure, or union.

The derived user-defined type must be declared as a class or structure.


Compiler Error C2571

'identifier' : union cannot have virtual function 'identifier'

The specified union was declared to have a virtual function.

Virtual functions can only be used with a class or structure but not with a union. Change the specified union to a class or structure or make it a nonvirtual function.


Compiler Error C2572

'identifier1::identifier2' : redefinition of default parameter : parameter identifier3

The specified default parameter in a member function was redefined.

A default parameter cannot be redefined. If another value for the parameter is required, then the default parameter should be left undefined.


Compiler Error C2573

'identifier' : simple type cast must have exactly one expression

The specified conversion had a wrong number of actual parameters.

The following is an example of this error:

void func()
{
  int i = int();     // error, no actual parameters
  int j = int( 1.0 ) // OK
}


Compiler Error C2574

'identifier' : illegal static destructor declaration

The specified destructor was declared as static.

Destructors cannot be declared as static.


Compiler Error C2575

'identifier' : only member functions and bases can be virtual

The specified global function or class was declared as virtual.

The keyword virtual refers only to members of a class or structure. A global function or a class or structure that is not a base class cannot be declared as virtual.


Compiler Error C2576

'identifier' : virtual used for static member function

A static member function was declared as virtual.

The virtual function mechanism relies on the specific object that calls the function to determine which virtual function is used. Since this is not possible for static functions, they cannot be declared as virtual.


Compiler Error C2577

'identifier' : destructor cannot return a value

The specified destructor returned a value.

A destructor cannot return a value of any type. This error is caused by defining a destructor that returns a value of any type, including a void return type.

This error can be eliminated by removing the return statement from the destructor definition.


Compiler Error C2579

'identifier1::identifier2(identifier3)' : parameter list not sufficiently different from 'identifier1::identifier2(identifier4)'

The parameter lists for the specified functions were not sufficiently different.

The formal parameter lists of overloaded functions must all be different.


Compiler Error C2580

redefinition of class name 'identifier'

The specified class, structure, or union was already defined.

A class, structure, or union can be defined only once.


Compiler Error C2581

'identifier' : static 'operator =' function is illegal

The assignment operator, operator=(), was declared as static.

The assignment operator cannot be declared as static.


Compiler Error C2582

'identifier' : 'operator =' function is unavailable

No assignment operator, operator=(), was defined for the specified class.

If any assignment operator has been defined that takes the class as a parameter, then a default assignment operator will not be generated by the compiler. The assignment operator must be explicitly defined for each class and is not inherited by derived classes.

For more information, see Compiler Errors when Implementing a CObject-Derived Class.


Compiler Error C2583

'identifier' : 'const/volatile' 'this' pointer is illegal for constructors/destructors

A constructor or destructor was declared with a const or volatile specifier.

The const and volatile declaration specifiers cannot be used for constructors or destructors.


Compiler Error C2584

'identifier1' : direct base 'identifier2' is inaccessible; already a base of 'identifier3'

The specified derived class (identifier1) was derived from a direct base class (identifier3) that was already a base class of the derived class (identifier2).

A class (or structure) cannot use the same class more than once if it is already a direct base class in the hierarchy (a class mentioned in the list of base classes for the derived class). For example:

class A
{
public:
   A() {;}
};

class B : public A
{
public:
   B() {;}
};

class C : public B, virtual public A
// error: A is already a direct base class of B
{
public:
   C() {;}
};

In order to use class A as a base class of both B and C, it must be virtually inherited by each class. For example:

class A
{
public:
   A() {;}
};

class B : virtual public A
{
public:
   B() {;}
};

class C : public B, virtual public A
// ok: A is virtually inherited by both B and C
{
public:
   C() {;}
};


Compiler Error C2585

explicit conversion to 'type' is ambiguous

The type conversion could produce more than one result. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

Ambiguous conversion can result when converting from a class (or structure) type based on multiple inheritance. If the same base class is inherited more than once, the conversion function or operator must specify which of the inherited classes to use in the conversion. The scope resolution operator (::) can be used to do this.

Ambiguous conversion can also be caused when a conversion operator and a constructor making the same conversion have been defined.


Compiler Error C2586

incorrect user-defined conversion syntax : illegal indirections

Indirection of a conversion operator is not allowed.

The following is an example of this error:

class C
{
   operator int();   // error, indirection on the operator
};

The following is a correct example:

typedef int pINT_t;
class D
{
   operator pINT_t();  // OK
};


Compiler Error C2587

'identifier' : illegal use of local variable as default parameter

A local variable was illegally used as a default parameter.

The following is an example of this error:

int i;
void func();
{
   int j;
   extern void func2( int k = j );  // error, local variable
   extern void func2( int k = i );  // OK
}


Compiler Error C2588

'::~identifier' : illegal global destructor

The specified destructor was not defined for a class, structure, or union.

A destructor can be defined only for a class, structure, or union.

This error can be caused by omitting the name of a class, structure, or union on the left side of the scope resolution operator (::).

The following is an example of this error:

~F();  // error


Compiler Error C2589

'identifier' : illegal token on right side of '::'

The token on the right side of the scope resolution operator (::) was not legal.

Only a member of a class (or structure or union) can be on the right side of the scope resolution operator if a class name is on the left side. Otherwise, any global identifier can be on the right side.


Compiler Error C2590

'identifier' : ambiguous user-defined conversions in switch expression

The specified switch expression could not be converted to an integral type.

An expression in a switch expression must unambiguously convert to an integral type.

Ambiguous conversion can be caused when a conversion operator and a constructor making the same conversion have been defined.


Compiler Error C2591

'identifier' : ambiguous user-defined conversions in conditional expression

The specified conditional expression could not be converted to an integral type.

An expression in a conditional expression must unambiguously convert to an integral type.

Ambiguous conversion can be caused when a conversion operator and a constructor making the same conversion have been defined.


Compiler Error C2592

no legal conversion of initialization expression to type 'type'

The value of the initialization expression could not be converted to the specified type. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

A conversion operator may need to be supplied to make the required cast.


Compiler Error C2593

'operator identifier' is ambiguous

More than one possible operator was defined for the specified overloaded operator.

An explicit cast of one or more of the actual parameters can resolve the ambiguity.

The following is an example of this error:

struct A {};
struct B : A {};
struct X {};
struct D : B, X {};
void operator+( X, X );
void operator+( A, B );
D d;
void main()
{
   d +  d;         // error, D has an A, B, and X
   (X)d + (X)d;    // OK, uses operator+( X, X )
}

This error can also be caused by serializing a floating-point variable using a CArchive object. The error identifies the operator << as being ambiguous. The only primitive C++ types that CArchive can serialize are the fixed-size types BYTE, WORD, DWORD, and LONG. All integer types can be cast to one of these types for serialization. Floating-point types must be handled differently. They can be archived using CArchive's member function CArchive::Write(). The following example shows how to archive a floating-point variable 'f' to an archive 'ar':

ar.Write(&f, sizeof( float ));


Compiler Error C2594

'operator' : ambiguous conversions from 'type1' to 'type1'

No conversion from one specified type to the other was more direct than any other. It may be necessary to define or specify an explicit conversion.


Compiler Error C2595

'identifier' : qualified name already has a constructor

A constructor was already defined for the specified nested class, structure, or union.

Only one constructor can be defined for a class, structure, or union.


Compiler Error C2596

'identifier' : qualified name already has a destructor

A destructor was already defined for the specified nested class, structure, or union.

Only one destructor can be defined for a class, structure, or union.


Compiler Error C2597

illegal reference to data member 'member' in a static member function

The identifier you specified is a member of the class. However, it is nonstatic and the current function is a static member function. To access the member, an instance of the class must be provided and accessed using the . or -> operators.

The specified identifier was not a member of a class, structure, or union.

A member access operator (. or ->) was used to refer to a function that was not defined as a member of the class, structure, or union.

The following code in a .cpp file will generate C2597:

struct s1 {
   static void   func();
   int   i;
};

void s1::func()
{
   i = 1;   // error C2597 here
}


Compiler Error C2598

linkage specification must be at global scope

The linkage specifier was declared at local scope.

The following is an example of this error:

void func()
{
   extern "C" int func2();   // error, linkage declared in
   .                         //   block at local scope
   .
   .
}
extern "C" int func( int i );  // OK


Compiler Error C2599

'function' : local functions are not supported

The specified function was defined inside the body of another function. This error can be caused by omitting the closing curly brace (}) in a function definition.

The following is an example of this error:

void func1()
{
                  // Missing a closing curly brace here
void func2() {}   // Error detected on this line

void func3()
{
void func4() {}   // Error detected on this line
}                 // Local functions not allowed


Compiler Errors C2600 Through C2699

The following topics cover compiler errors C2600 through C2699.


Compiler Error C2600

'name' : uses 'identifier' in local class 'class' causing compiler-generated special member functions

The declaration of the member identifier caused the compiler to generate a member function, such as an assignment operator or a default constructor (a constructor taking no parameters), for the specified class. However, local classes cannot define member functions.

Members that are declared with the const modifier or that are references require the compiler to generate an assignment operator and a default constructor. This is because such members can only be initialized, not assigned new values.

The following is an example of this error:

void f()
{
   class C         // local class
   {
      const int i; // error: const member
   };

   C c;  // constructor needed to initialize c.i
}


Compiler Error C2601

'function name' : local function definitions are illegal

An attempt was made to define a function within a function.

The following is an example that will generate this error:

int main()
{
   int i = 0;

   int funcname(int j)
   {
      j++;
      return j;
   }

   i = funcname(i);
   return 0;
}

If you move the function into the global space, outside the main() function, the program will compile and run.


Compiler Error C2602

'class::identifier' is not a member of a base class of 'class'

An access declaration was made for the specified identifier, but it is not a member of a base class.

A member of a class or structure cannot be accessed in another class that is not derived from the member's class.

The following is an example of this error:

struct X
{
   int x;
};
struct A
{
   int a;
};
struct B : public A
{
   X::x;       // error, B is not derived from X
   A::a;       // OK
};


Compiler Error C2603

illegal access declaration: 'class1' is not a direct base of 'class2'

The specified class or structure (class2) contained an access declaration for a member of a class or structure (class1) that was not a direct base.

To change the access to a member of an indirect base class, use its qualified name in the public or protected part of the derived class declaration. The qualified name must specify a direct base class.

The following is an example of this error:

struct A
{
   int a, a2;
};
struct B : A {};
struct C : B
{
   A::a2;  // error, A is not a direct base
   B::a;   // OK, qualified name specifies a direct base
};


Compiler Error C2605

overloaded functions 'class::function' do not have same access

The specified overloaded functions have different access but but were named in an access declaration.

Access cannot be adjusted for overloaded functions that do not have the same access.

The following are examples of this error:

struct X
{
private:
   int f();
protected:
   int f(int);
public:
   int f(int,int);
};
struct A : public X
{
protected:
   X::f;       // error
public:
   X::f;       // error
};
struct B : protected X
{
protected:
   X::f;       // error
public:
   X::f;       // error
};
struct C : private X
{
protected:
   X::f;       // error
public:
   X::f;       // error
};


Compiler Error C2606

'class::identifier': illegal private access declaration

The access of the specified identifier was adjusted in the private part of the derived class declaration.

The access to a member of a base class in a derived class can only be adjusted by mentioning its name in the public or protected part of the derived class declaration.

The following are examples of this error:

struct X
{
private:
   int priv;
protected:
   int prot;
public:
   int pub;
};
struct A : public X
{
private:
   X::priv;    // error
   X::prot;    // error
   X::pub;     // error
};
struct B : protected X
{
private:
   X::priv;    // error
   X::prot;    // error
   X::pub;     // error
};
struct C : private X
{
private:
   X::priv;    // error
   X::prot;    // error
   X::pub;     // error
};


Compiler Error C2607

'initializing' : cannot implicitly convert a 'type1' to a 'type2' that is not const

In C++, you create a reference to another object by initializing the reference using the address-of operator (&). Creating a reference object allows you to modify the original object by changing the reference object. It is similar to modifying a variable in C through a pointer to that variable, but the notation is cleaner because you do not need to dereference the pointer to access the variable.

If you try to create a reference (“initializing a reference”) to an object of another type, the compiler will issue error C2607. For example, if you create an int reference to a float variable the compiler will issue this error unless the float variable is const. Otherwise, every time you modified the int variable, the compiler would have to supply a conversion to the float variable; and every time you modified the float variable, the compiler would also have to supply a conversion to the int variable.

The reference to type2 must be one of the following:

  • An l-value of type type2

  • A type derived from type2 for which type2 is an accessible base

The following is an example of this error:

float f;
int& ri2 = f; // error, f is not an int l-value


Compiler Error C2608

illegal reference cast - operand not an l-value

The reference could not be cast.

This error occurs when a temporary copy of the referenced value cannot be generated.

The following is an example of this error:

struct C
{
   int mem;
   operator int();
};
struct D
{
   operator C();
   void memfunc();
};
D aD[10];
void D::memfunc()
{
   C aC = ( C& )( aD + 1 );   // error
}


Compiler Error C2609

'conversion' : cannot implicitly convert a non-lvalue 'type1' function return to a 'type2' that is not const

A reference cannot be initialized from a non-lvalue function return.

This is an error when the ANSI compatibility option is enabled (/Za) and a warning when the Microsoft extensions are enabled (/Ze).

The following is an example of this error:

struct X
{
    X( int );
};
X f();
X& r = f();   // error


Compiler Error C2610

identifier 'identifier' can never be instantiated; user-defined constructor is required

The specified class cannot be properly initialized.

This error occurs when a constructor cannot be created for the class. A user-defined constructor should be defined.


Compiler Error C2611

'token' : illegal following '~' (expected identifier)

The specified token was not an identifier.

The following is an example of this error:

class C
{
   C::~operator int();    // error
   ~C();                  // OK, destructor declaration
};


Compiler Error C2612

trailing ',' illegal in base/member initializer list

A comma (,) was placed after the last base or member in an initializer list.

The following is an example of this error:

class A
{
public:
   int i;
   A( int ia ) : i( ia ), {}; // error, extra comma
};
class B
{
public:
   int i;
   B( int ib ) : i( ib ) {};  // OK
};


Compiler Error C2613

trailing ',' illegal in base class list

A comma (,) was placed after the last base in a base class list.

The following is an example of this error:

class A {};
class B : public A, {};  // error, extra comma
class C : public A {};   // OK


Compiler Error C2614

'class1' : illegal member initialization: 'class2' is not a base or member

A class in an initialization list was not a base class or member.

Only a member or base class can be in the initialization list for a class or structure.

The following is an example of this error:

class A
{
public:
   int i;
   A( int ia ) : B( i ) {};  // error, B is not a member of A
};


Compiler Error C2616

'conversion' : cannot implicitly convert a non-lvalue 'type1' to a 'type2' that is not const

A reference cannot be initialized from a non-lvalue.

This is an error when the ANSI compatibility option is enabled (/Za) and a warning when the Microsoft extensions are enabled (/Ze).


Compiler Error C2617

'function' : inconsistent return statement

The specified function did not have a return type declared, and a previous return statement did not supply a value.

The function's return type should be declared.

The following is an example of this error:

int i;
func()                   // no return type prototype
{
   if( i ) return;       // no return value
   else return( 1 );     // error detected on this line
}


Compiler Error C2618

local classes cannot have base classes

There was an attempt to declare a local class derived from another class. A local class cannot have a base class, even if the base class itself has file scope.

The following is an example of this error:

class A { };
void f()
{
    class B : public A {};   // error
}


Compiler Error C2619

union 'union' : cannot have static member variable 'identifier'

The specified union member was declared as static.

A union cannot have a static data member.

The following is an example of this error:

void func()
{
   union
   {
   static int j; // error, j is static
   int i;        // OK
   };
}


Compiler Error C2620

union 'union' : member 'identifier' has user-defined constructor or non-trivial default constructor

The specified union member was declared with a default constructor.

A union member is not allowed to have a default constructor.

The following is an example of this error:

class A
{
   A();      // A has a default constructor
};
union U
{
   A a;      // error
};


Compiler Error C2621

union 'union' : member 'identifier' has copy constructor

The specified union member was declared with a copy constructor.

A union member is not allowed to have a copy constructor.

The following is an example of this error:

class A
{
   A( const A& );  // A has a copy constructor
};
union U
{
   A a;            // error
};


Compiler Error C2622

union 'union' : member 'identifier' has assignment operator

The specified union member was declared with an assignment operator, operator=().

A union member is not allowed to have an assignment operator.

The following is an example of this error:

class A
{
   A& operator= ( const A& );  // A's assignment operator
};
union U
{
   A a;                        // error
};


Compiler Error C2623

union 'union' : member 'union' has destructor

The specified union member was declared with a destructor, which is not allowed.

The following is an example of this error:

class A
{
   ~A();    // A has a destructor
};
union U
{
   A a;     // error
};


Compiler Error C2624

local classes cannot be used to declare 'extern' variables

A local class or structure cannot be used to declare extern variables. The following example generates this error:

void main(void)
{
struct C {...};
extern C ac;   //error
}


Compiler Error C2625

anonymous union did not declare any non-static data members

Unions cannot have static data members.

The following is an example of this error:

static union {};         // error
static union { int i; }; // OK


Compiler Error C2626

anonymous union defines protected/private member 'identifier'

The specified member was declared with protected or private access.

A member of an anonymous union must have public access.

The following are an examples of this error:

void main()
{
   union
   {
   public:
      int i;     // OK, i is public
   protected:
      int j;     // error, j is protected
   private:
      int k;     // error, k is private
   };
}


Compiler Error C2627

member function defined in unnamed class

The specified function was declared in an anonymous union.

An anonymous union cannot have member functions.

The following is an example of this error:

void main()
{
    union
       int i;
       void func( void );     // error, union is anonymous
    };
    union U
       void func2( void );    // OK
    };
}


Compiler Error C2628

'type1' followed by 'type2' is illegal (did you forget a ';'?)

A section of code between the two specified types was incorrect.

This error can be caused by a missing semicolon.

The following is an example of this error:

class C
{
public:
   void func( void ) {;}
}                         // semicolon is missing here
void main() {}            // error detected on this line


Compiler Error C2629

unexpected 'token ('

A syntax error made the statement ambiguous.

This error can be caused by mixing declaration and expression syntax.

The following is an example of this error:

class B
{
   B( &B );  // error, misplaced &
   B( B& );  // OK
};


Compiler Error C2630

'symbol' found in what should be a comma-separated list

The specified symbol was used in a context that requires a comma-separated list.

The following is an example of this error:

class D
{
   public:
   D(int);
};
class E
{
   public:
   E(int);
};
class C : public D, public E   // OK
{
   C();
};
C::C() : D(0) ; E(0) { }       // error


Compiler Error C2631

'class' : destructors not allowed a return type

A destructor in the specified class, structure, or union was declared with a return type.

A destructor cannot be declared with a return type.

The following are examples of this error:

class C
{
   int ~C();   // error, returns int
   void ~C();  // error, returns void
   ~C();       // OK
};


Compiler Error C2632

'type1' followed by 'type2' is illegal

Two type specifiers had missing code between them.

The following is an example of this error:

int float i;   // error


Compiler Error C2633

'identifier' : 'inline' is the only legal storage class for constructors

The constructor was declared as other than inline.

The following is an example of this error:

class C
{
   extern C();  // error, not inline
};


Compiler Error C2634

'&class::member' : pointer to reference member is illegal

A pointer to a reference member was declared.

The following is an example of this error:

int mem;
struct S
{
   S() : rf(mem) { }
   int &rf;
};
int (S::*pdm) = &S::rf;  // error


Compiler Error C2635

cannot convert an 'identifier1*' to an 'identifier2*'; conversion from a virtual base class is implied

The specified conversion required a cast from a virtual base class to a derived class.

Casting from a virtual base class to a derived class is not allowed.


Compiler Error C2636

'identifier' : pointer to reference member is illegal

A pointer to a reference member was declared.

The following is an example of this error:

struct S {};
int &S::*prs;       // error


Compiler Error C2637

'identifier' : cannot modify pointers to data members

The specified pointer to a data member was modified.

The following is an example of this error:

struct S {};
int __pascal S::*pms;     // error


Compiler Error C2638

'identifier' : __based modifier illegal on pointer to member

The __based modifier was specifed for a pointer to a member.

The __based modifier can not be used for pointers to members.

The following is an example of this error:

void *a;

class C
{
public:
   int i;
   int j;
   int func();
};
int __based (a) C::* cpi = &C::i;  // error
int (__based (a) C::* cpf)() = &C::func; // error


Compiler Error C2639

compiler generated default constructor required by unnamed class

A default constructor was required for an unnamed class, structure, or union. A name is required for a constructor to be generated.

The following is an example of this error:

class A
{
public:
   A();      // default constructor declaration
};

class C
{
public:
   struct    // unnamed struct
   {
      A a;
   } s1;     // error detected here
   struct S  // named struct
   {
      A a;
   } s2;     // OK
};


Compiler Error C2640

'identifier' : __based modifier illegal on reference

There was an attempt to use the __based modifier on a reference. The __based modifier can only be used on pointers.

The following is an example of this error:

void f(int i)
{
    void *vp;
    int _based(vp) &vr = I;  // error
}


Compiler Error C2641

illegal pointer to member cast across virtual inheritance path

A pointer to a member was cast to a base class that was inherited using virtual inheritance.

The following is an example of this error:

struct V {};
struct A : virtual V {};
int A::*pma;
int V::*pmv = (int V::*)pma;      // error


Compiler Error C2642

cast to pointer to member must be from related pointer to member

A pointer to a member of one class was cast to a pointer to a member of another class (or structure) that was not a base class or derived class (of the first class).

In MFC applications this error may be caused by a mismatch between the function declarations in the message map and the function prototypes declared in the AFXWIN.H file. Check your message map functions against the prototypes in AFXWIN.H.

The following is an example of this error:

class B
{
    public:
        int b;
};

class C {};

class D : public B
{
    public:
        int d;
};

int C::* cpb = (int C::*)&B::b;  // error
int D::* dpb = (int D::*)&B::b;  // OK, B is a base class of D
int B::* bpd = (int B::*)&D::d;  // OK


Compiler Error C2643

illegal cast from pointer to member

A pointer to a member of a class, structure, or union was cast to a different type.

The following is an example of this error:

class C
{
public:
   int i;
   operator int*() { return &i; }
};
int C::* cpi = (int*)&C::i; // error
int C::* cpi2 = &C::i;      // OK


Compiler Error C2644

basis class 'class' for pointer to member has not been defined

A pointer was declared that pointed to a class that was declared but not defined.

The following is an example of this error:

class C;
int C::* cp; // error, C has not been defined
class D {};
int D::*dp;  // OK


Compiler Error C2645

no qualified name for pointer to member (found ':: *')

The pointer to member declaration did not specify a class.

The declaration of a pointer to a member of a class (or structure or union) must specify the name of the class.

The following is an example of this error:

class A {};
int ::* cp;    // error, class not specifed
int B::* bp    // error, B not defined
int A::* ap;   // OK


Compiler Error C2646

global anonymous unions must be declared static

The anonymous union had global scope but was not declared as static.

The following is an example of this error:

union { int i; };         // error, not static
static union { int j; };  // OK
union U { int i; };       // OK, not anonymous


Compiler Error C2647

'operator': cannot dereference a 'type1' on a 'type2'

The left-hand side of a pointer to member operator (either '->*' or '.*') could not be implicitly converted to a type related to the right-hand side of the operator.

The following is an example of this error:

class C {};
class D {};

void main()
{
   D d, *pd;
   C c, *pc;
   int C::*pmc;

   pd->*pmc = 0;   // error
   d.*pmc = 0;   // error
   pc->*pmc = 0;   // okay
   c.*pmc = 0;   // okay
}


Compiler Error C2648

'identifier' : use of member as default parameter requires static member

The specified nonstatic member was used as a default parameter.

The following is an example of this error:

class C
{
public:
   int i;
   static int j;
   void func1( int i = i );  // error, i is not static
   void func2( int i = j );  // OK, uses static j
};


Compiler Error C2649

'identifier' : is not a 'class-key'

The specified class, structure, or union declaration used an incorrect tag.

The following is an example of this error:

struct S
{
   int i;
};
class S::i c;   // error


Compiler Error C2650

'operator' : cannot be a virtual function

The specified operator was declared as virtual.

The operators new and delete cannot be virtual because they are static member functions.

The following is an example of this error:

class A
{
   virtual void* operator new( unsigned int ); // error
};


Compiler Error C2652

'identifier' : illegal copy constructor: first parameter must not be an 'identifier'

The first parameter in the specified copy constructor was the same type as the class, structure, or union for which it was defined.

A copy constructor for a type can take a reference to the type as the first parameter but not the type itself.

The following is an example of this error:

class A
{
   A( A );     // error, takes an A
};
class B
{
   B( B& );    // OK, reference to B
};


Compiler Error C2653

'identifier' : is not a class or namespace name

The specified identifier was not a class, structure, union, or namespace name.

An identifier that was not a class, structure, union, or namespace was accessed using incorrect syntax.

The following is an example of this error:

int x;
int main()
{
   return x::i; // error
}


Compiler Error C2654

'identifier' : attempt to access member outside a member function

The specifed identifier was accessed in a declaration.

Member data can only be accessed in member functions.

This error can be caused by trying to initialize variables in a declaration. A constructor should be used for this purpose.

The following is an example of this error:

class A
{
   int i;
   int j = i;  // error, access outside function
   void setj( void ) { j = i ; }  // OK, access in function
   A( int ai )
   {
      i = ai;  // OK, initializes i and j
      j = i;
   }
} a( 1 );


Compiler Error C2655

'identifier' : definition or redeclaration illegal in current scope

The specified identifier was redeclared or redefined at nonglobal scope.

An identifier can only be redeclared at global scope.

The following is an example of this error:

class A {};
class B
{
public:
   static int i;
};
void main()
{
   A B::i;  // error
}


Compiler Error C2656

'function' : function not allowed as a bit field

The specified function was declared as a member of a bit field.

This error can be caused by a syntax error in a constructor initializer list.


Compiler Error C2657

'class::*' found at the start of a statement (did you forget to specify a type?)

The line began with the specified pointer to member identifier.

This error can be caused by omitting a type specifier in the declaration of a pointer to a member.

The following is an example of this error:

class C {};
void main() {
   C::* pmc1;        // error
   void C::* pmc2;   // OK
}


Compiler Error C2658

multiple conversions : 'type1(type2)' and 'type1::operator type2()'

The conversion was ambiguous because it could be done with either the specified constuctor or the specifed conversion operator.

The following is an example of this error:

struct A;
struct B
{
   B(A);
   B();
};
struct A
{
   operator B();
};
A a;
B b = B(a);  // error


Compiler Error C2659

'operator' : overloaded function as left operand

An overloaded function was on the left side of the specified operator.

The following is an example of this error:

int func( int );
int func( double );
void main()
{
   func = 10;  // error
}


Compiler Error C2660

'function' : function does not take number parameters

The specified function was called with an incorrect number of actual parameters.

Tips

  • The most typical cause of this error is calling a function with the incorrect number of actual parameters. The following example demonstrates this:
    void func( int, int );
void main()
{
   func( 1 );     // error, func( int ) not declared
   func( 1, 0 );  // OK, func( int, int ) was declared
}
  • A problem similar to the one shown above occurs when you mistakenly call a Windows API function directly from within an MFC member function, rather than calling the equivalent MFC member function of the same name. Since the two functions are identical in name this error may occur frequently. Either of the two following methods will solve this error:
    • Adjust the function call to conform to the format of the member function call.

    • Use the scope resolution operator (::) to tell the compiler to look for the function name in the global name space.


Compiler Error C2661

'function' : no overloaded function takes number parameters

The specified overloaded function was not declared for the given number of parameters.

This error can be caused by calling the function with incorrect actual parameters or by omitting a function declaration.

The following is an example of this error:

void func( int );
void func( int, int );
void main()
{
   func( );      // error, func( void ) was not declared
   func( 1 );    // OK, func( int ) was declared
}


Compiler Error C2662

'function' : cannot convert 'this' pointer from 'type1' to 'type2'

The compiler could not convert the this pointer from type1 to type2.

This error may be caused by invoking a non-const member function on a const object. To correct the problem, remove the const from the object declaration or add const to the member function.

The following is an example of this error:

class C
{
public:
   void func1();
   void func2() const;
} const c;

void main()
{
   c.func1();  // error
   c.func2();  // no error
}


Compiler Error C2663

'function' : number overloads have no legal conversions for 'this' pointer

The compiler could not convert the this pointer to any of the overloaded versions of the member function.

This error may be caused by invoking a non-const member function on a const object. To correct the problem, remove the const from the object declaration or add const to one of the member function overloads.

The following is an example of this error:

class C {
public:
   void foo() volatile;
   void foo(); // adding const here would fix problem
};

const C *pcc;

void main()
{
   pcc->foo();      // error
}


Compiler Error C2664

'function' : cannot convert parameter number from 'type1' to 'type2'

The specified parameter of the specified function could not be converted to the required type. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The following is an example of this error:

class A {} a;
func( int, A );
void main()
{
   func( 1, 1 );  // error, no conversion from int to A
}

Tips

Recheck the prototype for the given function and correct the argument noted in the error message. If necessary, an explicit conversion may need to be supplied.


Compiler Error C2665

'function' : none of the number1 overloads can convert parameter number2 from type 'type'

The specified parameter of the overloaded function could not be converted to the required type. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

You may need to supply a conversion operator or explicit conversion.


Compiler Error C2666

'identifier' : number overloads have similar conversions

The specified overloaded function or operator was ambiguous. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

This error is caused by formal parameter lists that are too similar to resolve ambiguity.

An explicit cast of one or more of the actual parameters can resolve the ambiguity.

The following is an example of this error:

void func( int, float ) {};
void func( float, int ) {};
func( 1, 1 );        // error, same conversion for each func
func( 1, (float)1 )  // OK


Compiler Error C2667

'function' : none of number overload have a best conversion

The specified overloaded ambiguous function call could not be resolved. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The conversion required to match the actual parameters in the function call to one of the overloaded functions must be strictly better than the conversions required by all the other overloaded functions.


Compiler Error C2668

'function' : ambiguous call to overloaded function

The specified overloaded function call could not be resolved. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

An explicit cast of one or more of the actual parameters can resolve the ambiguity.

The following is an example of this error:

struct A {};
struct B : A {};
struct X {};
struct D : B, X {};

void func( X, X );
void func( A, B );
D d;
void main()
{
   func( d, d );        // error, D has an A, B, and X
   func( (X)d, (X)d );  // OK, uses func( X, X )
}


Compiler Error C2669

illegal to overload member 'operator delete' with different number of formal arguments

A class defined two versions of the operator delete function. A given class can define only one.

The following is an example of this error:

class C
{
   void operator delete(void *);
   void operator delete(void *, size_t); // error
};


Compiler Error C2670

'identifier' : the template function cannot convert parameter number from type 'type'

The specified parameter of the specified function could not be converted to the required type.

You may need to supply an explicit conversion.


Compiler Error C2671

'function' : static member functions do not have 'this' pointers

The specified static member function could not access a this pointer.

The following is an example of this error:

struct S
{
   static S* const func() { return this; }  // error
};


Compiler Error C2672

'function' : new/delete member functions do not have 'this' pointers

The specified new or delete operator did not have a this pointer to access.

The following is an example of this error:

class C
{
   void* operator new( unsigned int )
   {
      this = 10;      // error  return 0;
   }
};


Compiler Error C2673

'function' : global functions do not have 'this' pointers

The specified global function did not have a this pointer to access.

The following is an example of this error:

void main()
{
   this = 0;  // error
}


Compiler Error C2674

'operator' : no acceptable conversions from 'type1' to 'type2'

A conversion was not defined to convert an operand to the required type. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

Define a constructor or conversion operator to make the required conversion.

The following is an example of this error:

class C
{
   public:
   C();       // no constructor with an int argument
} c;
class D
{
   public:
   D( int );
   D();
} d;
void main()
{
   c = 10;    // error
   d = 10;    // OK
}


Compiler Error C2675

unary 'operator' : 'type' does not define this operator or a conversion to a type acceptable to the predefined operator

The specified operator could not be used in its predefined form. To use the operator you must overload it for the apropriate type, or define a conversion to a type for which the operator is defined. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The following is an example of this error:

class C
{
   public:
   C();
} c;

class D
{
   public:
   D();
   operator !();
} d;

void main()
{
   !c;   // error
   !d;    // OK, operator !() defined
}


Compiler Error C2676

binary 'operator' : 'type' does not define this operator or a conversion to a type acceptable to the predefined operator

The specified operator could not be used in its predefined form. To use the operator you must overload it for the apropriate type, or define a conversion to a type for which the operator is defined. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The following is an example of this error:

class C
{
   public:
   C();
} c;

class D
{
   public:
   D();
   D operator <<( C& );
} d;
void main()
{
   d >> c;   // error
   d << c;   // OK, operator << defined
}


Compiler Error C2677

binary 'operator' : no global operator defined which takes type 'type' (or there is no acceptable conversion)

The specified operator was not defined for the specified type. To use the operator you must overload it for the apropriate type, or define a conversion to a type for which the operator is defined. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The following is an example of this error:

class C
{
   public:
   C();
} c;

class D
{
   public:
   D();
   operator int();
} d;

void main()
{
   1 >> c;   // error
   1 >> d;   // OK, operator int() defined
}


Compiler Error C2678

binary 'operator' : no operator defined which takes a left-hand operand of type 'type' (or there is no acceptable conversion)

The specified operator was not defined for the specified type. To use the operator you must overload it for the apropriate type, or define a conversion to a type for which the operator is defined. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The following is an example of this error:

class   C
{
   public: C();
};

void main()
{
   C   aC;
   aC + 12;      // error
   }


Compiler Error C2679

binary 'operator' : no operator defined which takes a right-hand operand of type 'type' (or there is no acceptable conversion)

Define a constructor or conversion operator to make the required conversion. If you’ve encountered this error on code which compiled with an earlier version of Visual C++, please read Technote: Improved Conformance to ANSI C++ for more information.

The following is an example of this error:

class C
{
   public:
   C();       // no constructor with an int argument
} c;
class D
{
   public:
   D( int );
   D();
} d;
void main()
{
   c = 10;    // error
   d = 10;    // OK
}


Compiler Error C2680

'type' : invalid target type for name

An attempt was made to use a casting operator to convert to a type that is not a pointer type or a reference type. The dynamic_cast operator can be used only for converting to pointers or references.

The following is an example of this error:

class A { virtual void f(); };
class B : public A {};

void g(B b)
{
    A a;
    a = dynamic_cast<A>(b);  // error
}


Compiler Error C2681

'type' : invalid expression type for name

An attempt was made to use a casting operator to convert from an invalid type. For example, if you use the dynamic_cast operator to convert an expression to a pointer type, the source expression must be a pointer.

The following is an example of this error:

class A { virtual void f(); };

void g(int i)
{
    A* pa;
    pa = dynamic_cast<A*>(i);  // error
}


Compiler Error C2682

cannot use name to convert from 'type1' to 'type2'

An attempt was made to use a casting operator to convert between incompatible types. For example, you cannot cast use the dynamic_cast operator to convert a pointer to a reference.

Also note that the dynamic_cast operator cannot be used to cast away qualifiers. All qualifiers on the types must match. You can, however, use the const_cast operator to remove attributes such as const, volatile, or __unaligned.

The following is an example of this error:

class A { virtual void f(); };
class B: public A {};

void g(A* pa)
{
    B& rb = dynamic_cast<B&>(pa); // error
}


Compiler Error C2683

dynamic_cast : 'class' is not a polymorphic type

The dynamic_cast operator cannot be used to convert from a non-polymorphic class, that is, a class that does not define any virtual functions.

You can use the static_cast operator to perform conversions of non-polymorphic types; note, however, that static_cast does not perform a run-time check.

The following is an example of this error:

class B { };
class D : public B {  };

void f(B* pb)
{
    D* pd1 = dynamic_cast<D*>(pb);  // error
}


Technote: Improved Conformance to ANSI C++

As a result of improved C++ conformance, some constructs that used to compile will now give errors. Each error message that may result from some of these changes is flagged by "(new behavior; please see help)" at the end of the message. This doesn't mean that the error message has a new meaning; it means that the compiler may be diagnosing an error which it previously did not.

The errors affected are:

C2434 | C2440 | C2446 | C2553 | C2585 | C2592
C2664 | C2665 | C2666 | C2667 | C2668 | C2674
C2675 | C2676 | C2677 | C2678 | C2679 |

Overload Resolution Changes

Visual C++ overload resolution rules have been brought more in line with those specified in the draft C++ standard. This will allow some things to work that previously did not, but it also will result in ambiguities in code that compiled cleanly with earlier versions of Microsoft Visual C++.

Dereferencing a Reference is an Identity Conversion

Previous versions of Microsoft Visual C++ considered dereferencing a reference or binding to a reference to be a worse conversion than an exact match. These conversions (listed in the Annotated C++ Reference Manual as trivial conversions) are now considered to be identity.

For example:

void foo(const int);
void foo(int&);

void bar(void)
{
    int i;
    int &ri = i;
    foo(i);  // Accepted by VC2.0, VC1.x, rejected by VC4.0, error C2668
    foo(ri);  // Accepted by VC2.0, VC1.x, rejected by VC4.0, error C2668
}

User-Defined Conversions (UDCs) are Selected by 'this' Pointer Types

Previous versions of Visual C++ selected the user-defined conversion to call based on the conversion required to get from the result type of the UDC to the required type and ignored the conversion required for the 'this' pointer of the UDC. User-defined conversions are now selected based on the quality of match on the 'this' pointer. As a Microsoft extension (not currently flagged by /Za), the quality of the conversion from the UDC result to the target type is used as a tie-breaker in the event that the 'this' pointers match.

This change of behavior will catch some bad errors that previously had not been detected. For example:

struct C {
    // some class
};

struct D {
    // A class which wraps a C
    C myC;

    // Two user-defined conversion functions, one for
    //  using myC, and the other for modifying it
    operator C () { return myC; }   // conversion #1
    operator C& () { return myC; }   // conversion #2
};

// A function that takes a C
void func1(C);

// A function that has a D
void func2()
{
    D aD;

    func1(D);  // Error diagnosed in VC4.0: error C2664
}

The error in this case is that the user-defined conversion is ambiguous. This is because the conversion for the this-pointer is identical for both UDCs, and the result of the UDCs has an identical conversion. The following example (added to the previous one) illustrates another error:

// A function that wants to modify a C
void func3(C&);

// Some function that gets a D&
void func4(const D& aD)
{
    func3(aD);  // Error diagnosed in VC4.0: error C2664
}

This time, the error occurs because neither UDC can be called—the D object is const, but neither UDC takes a const this pointer.

The way to correct both these problems is to rewrite conversion #1 as follows:

operator C () const { return myC; }  // conversion #1a

or:

operator const C& () const { return myC; }  // conversion #1b

Both these conversions take a const this pointer, so they can be called for const objects. In addition, conversion #1b returns a reference to a const object, avoiding copy construction, but still ensuring that the original object will not be modified.

An additional, more subtle effect of this change is that user-defined conversions can silently change behavior. For example:

void foo(int);

struct C {
    operator int () const;
    operator long ();
};

void main(void)
{
    C aC;
    const C acC;

    foo(acC);  // calls "operator int() const"
    foo(aC);   // calls "operator int() const" in VC2.0,
               // but "operator long()" in VC4.0
}


Compiler Errors C2700 Through C2788

The following topics cover compiler errors C2700 through C2760.


Compiler Error C2700

'identifier' : cannot be thrown (use –W4 for more info)

The specified object cannot be thrown. For more diagnostic information on this error, compile with level-4 warnings enabled (/W4).


Compiler Error C2702

__except may not appear in termination block

An exception handler (__try/__except) cannot be nested inside a __finally block.

The following example causes this error:

int Counter;
void main ()
{
   __try {}
   __finally
   {
      __try {}
      __except( Counter ) {}    // error
   }
}


Compiler Error C2703

illegal __leave statement

A __leave statement must be within a __try block.

The following is an example of this error:

void main ()
{
   __leave;   //error
   __try
   {
      __leave;   //OK
   }
   __finally {}
}


Compiler Error C2704

'identifier' : __va_start intrinsic only allowed in varargs

The __va_start intrinsic was used in a function declaration for a function that did not take a variable number of arguments.


Compiler Error C2705

'identifier' : illegal jump into __try scope

Program control was transferred to the specified label within a __try block.

The following is an example of this error:

void main ()
{
goto trouble;
   __try {
   trouble: ;   //error
   }
   __finally {}
}


Compiler Error C2707

'identifier' : bad context for intrinsic function

The structured exception handling intrinsic functions are only valid in certain contexts. This is caused by one of the following conditions:

  • _exception_code() was called outside an exception filter or __except block

  • _exception_info() was called outside an exception filter

  • _abnormal_termination() was called outside a __finally block


Compiler Error C2708

'identifier' : actual parameters length in bytes differs from previous call or reference

A __stdcall function must be preceded by a prototype. If such a function is not preceded by a prototype, then the compiler takes the first call to this function as the prototype. This error occurs when the compiler encounters a call that does not match the implicit prototype.

To fix this error, add a prototype for the function.


Compiler Error C2709

'identifier' : formal parameter's length in bytes differs from previous declaration

The signature in a call to the specified function differed from its prototype.


Compiler Error C2710

cannot delete a pointer to a const object

A pointer to an object declared as const was illegally deleted using the delete operator.

The following is an example of this error:

const int* pci;
const int i = 0;
void main()
{
   pci = &i;
   delete pci;  // error, pci points to a const
}


Compiler Error C2711

cannot delete a pointer to a function

A pointer to a function was illegally deleted using the delete operator.

The following is an example of this error:

void (*pf)();
void func();
void main()
{
   pf = func;
   delete pf;   // error, pf points to a function
}


Compiler Error C2712

cannot use __try in functions that require object unwinding

You cannot have objects that require unwinding in a function with structured exception handling.

To avoid this error message, compile using the /GX- option.

The error can be avoided when using the /GX option by not having local variables or parameters with types that have destructors in a function that uses structured exception handling (SEH). Furthermore, SEH cannot be used in constructors or destructors if using /GX. Code that requires SEH can also be moved to another function in order to avoid the error.


Compiler Error C2713

only one form of exception handling permitted per function

You cannot use both __try/__except (structured exception handling) and try/catch (C++ exception handling) in the same function


Compiler Error C2720

'identifier' : 'specifier' storage-class specifier illegal on members

A storage class was illegally specified for the given identifier.

The following is an example of this error:

struct S
{
   static int i;
};
static S::i;   // error


Compiler Error C2721

'specifier' : storage-class specifier illegal between operator keyword and type

A type conversion cannot specify a storage class. User-defined type conversions apply to all storage classes.


Compiler Error C2722

'::operator' : illegal following operator command; use 'operator operator'

Either ::new or ::delete was redefined using the operator statement. Since the new and delete operators are global, the scope resolution operator (::) is meaningless in this context.

Remove the scope resolution operator preceding the given operator.


Compiler Error C2723

'function' : 'specifier' storage-class specifier illegal on function definition

The given specifier is not allowed on a function definition appearing outside of a class declaration. The virtual specifier can only be specified on a member function declaration appearing within the class declaration.

The following is an example of this error:

struct X
{
   virtual void f();
   virtual void g();
};
virtual void X::f() {} // error, virtual specifier
void X::g() {}         // OK


Compiler Error C2724

'identifier' : 'static' should not be used on member functions defined at file scope

A static member function was defined at file scope. Static member functions should be declared with external linkage.

This is a warning when Microsoft extensions are used (/Ze) and is an error when Microsoft extensions are disabled (/Za).

The following is an example of this error:

class C
{
   static void func();
};

static void C::func(){};    // error


Compiler Error C2730

'class' : cannot be a base class of itself

Recursive base classes are illegal.

Remove the base class specifier, or specify another class as a base class.


Compiler Error C2731

'identifier' : function cannot be overloaded

The functions main, WinMain, and LibMain cannot be overloaded.

The following is an example of this error:

extern "C" void WinMain(int, char *, char *);
void WinMain(int, short, char *, char*);       // error


Compiler Error C2732

linkage specification contradicts earlier specification for 'function'

The specified function was already declared with a different linkage specifier.

This error can be caused by different linkage specifiers found in include files.

Change the extern statements so that the linkages agree.

The following is an example of this error:

extern void func( void );      // implicit C++ linkage
extern "C" void func( void );  // error


Compiler Error C2733

second C linkage of overloaded function 'function' not allowed

More than one overloaded function was declared with C linkage.

When using C linkage, only one form of a given function can be made external.

Since overloaded functions have the same undecorated name, they cannot be used with C programs.


Compiler Error C2734

'identifier' : const object must be initialized if not extern

The specified identifier was declared as const but was not initialized.

An identifier must be initialized when declared as const unless it is declared as extern.

The following is an example of this error:

const int j;           // error
extern const int i;    // OK, declared as extern


Compiler Error C2735

'keyword' keyword is not permitted in formal parameter type specifier

The specified keyword was illegal in its context.

The following are examples of this error:

void main()
{
   int *myint;
   myint = new static int;     // error
   myint = new typedef int;    // error
   myint = new auto int;       // error
   myint = new register int;   // error
}


Compiler Error C2736

'keyword' keyword is not permitted in cast

The specified keyword was illegally used in a cast.

The following is an example of this error:

int main()
{
   return (virtual) 0;   // error
}


Compiler Error C2737

'class1' : base class 'class2' must be exported

A derived class class1 was exported, but its base class class2 was not.

If class1 is exported, class2 must also be exported.


Compiler Error C2750

'operator' : 'type'1 to 'type2'

The specified conversion was illegal.


Compiler Error C2758

'const' : must be initialized in constructor base/member initializer list

The given constant was not initialized with an initializer list in the object constructor. The compiler left the constant undefined.

If a const or reference member variable is not given a value when it is initialized, it must be given a value in the object constructor.


Compiler Error C2760

syntax error : expected 'name1' not 'name2'

A casting operator was used with an invalid operator.

The following is an example of this error:

class B { };
class D : public B {  };

void f(B* pb)
{
    D* pd1 = static_cast<D*>(pb);
    D* pd2 = static_cast<D*>=(pb); // error
    D* pd3 = static_cast<D*=(pb);  // error
}


Compiler Error C2770

#import expected a filename, found 'token'

The compiler expects to find “filename” or <filename> following the #import preprocessor directive. This error occurs when a token other than the filename is found.

For example:

#import “filename”      //correct
#import <filename>      //correct
#import filename      //incorrect, error C2770
#import =            //incorrect, error C2770


Compiler Error C2771

#import only permitted at global or namespace scope

The #import preprocessor directive is only allowed in the global or namespace scope. It is not allowed in, for example, a function or structure scope.


Compiler Error C2772

#import referenced a type from a missing type library; '__missing_type__' used as a place holder

While the compiler was processing the type library named by the #import directive, it encountered a referenced type defined in a secondary type library. In addition, this secondary type library could not be found, and the compiler could not send this typename to the type library headers. A dummy typename, "__missing_type__", was sent to the output instead. This will trigger additional errors as the type library headers are compiled.

This error occurs when the secondary type library is not properly registered or missing. When the compiler detects this error, it cannot determine the name of the missing secondary type library. Search for the string "__missing_type__" in the type library headers. This may help determine the name of the secondary type library.


Compiler Error C2773

#import only available in C++ compiler

Only the C++ compiler recognizes the #import preprocessor directive. Make sure the source file is specified as C++ (/TP).


Compiler Error C2774

'identifier' : no 'put' method is associated with this property

A structure or class data member declared with the property extended attribute does not have a put function specified, and this data member is used in an expression that tries to set its value. For example:

struct A {
   __declspec(property(get=GetProp)) int prop;
   int GetProp(void);
};

void f(A* pa, int val)
{
    pa->prop = val;      // error C2774
    pa->prop++;      // error C2774
}


Compiler Error C2775

'identifier' : no 'get' method is associated with this property

A structure or class data member declared with the property extended attribute does not have a get function specified, and this data member is used in an expression that tries to retrieve its value. For example:

struct A {
   __declspec(property(put=PutProp)) int prop;
   int PutProp(void);
};

int f(A* pa)
{
   int x = pa->prop;   // error C2775
   return x;
}


Compiler Error C2776

only one 'get' method can be specified per property

You can only specify one get function in the property extended attribute. This error occurs when multiple get functions are specified. For example:

struct A {
   __declspec(property(get=GetProp,get=GetPropToo))
      int prop;      // error C2776
   int GetProp(void);
   int GetPropToo(void);
};


Compiler Error C2777

only one 'put' method can be specified per property

You can only specify one put function in the property extended attribute. This error occurs when multiple put functions are specified. For example:

struct A {
   __declspec(property(put=PutProp,put=PutPropToo))
      int prop;      // error C2777
   int PutProp(void);
   int PutPropToo(void);
};


Compiler Error C2778

improperly formed GUID in __declspec(uuid())

An incorrect GUID is supplied to the uuid extended attribute. The supplied GUID must be a string of hexadecimal numbers with the following format:

// Correct:
struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) A { };
struct __declspec(uuid("{00000000-0000-0000-0000-000000000000}")) B { };

The example below generates this error:

// error C2778:
struct __declspec(uuid(" 00000000-0000-0000-0000-000000000000 ")) C { };
struct __declspec(uuid("00000000000000000000000000000000")) D { };

Strings recognized by the CLSIDFromString function, with or without the “{“ and “}” delimiters, are acceptable to the uuid extended attribute.


Compiler Error C2779

'declaration' : property methods can only be associated with non-static data members

This error occurs when the property extended attribute is applied to a static data member of a class or structure. For example:

struct A {
   static __declspec(property(put=PutProp))
      int prop;      // error C2779
   int PutProp(void);
};


Compiler Error C2780

'declaration' : expects value1 arguments - value2 provided

Too few arguments are provided to a call of a function template. For example:

template<class T> void f(T, T){ }
f(1);

This code will cause the compiler error.


Compiler Error C2781

'declaration' : expects at least value1 argument - value2 provided

Too few arguments are provide to a call of a function template with a variable parameter list. For example:

template<class T> void f(T, int, ...){ }
f(1);

In this case, the function can take more than two parameters. Only one parameter is provided in the function call.


Compiler Error C2782

'declaration' : template parameter 'identifier' is ambiguous

Compiler type deduction has detected that a template argument has an ambiguous type. For example:

template<class T> void f(T,T){ }
f(1, 'c');

The compiler is unable to deduce type T in the above function call, since the type T can be either int or char.


Compiler Error C2783

'declaration' : could not deduce template argument for 'identifier'

A template argument cannot be deduced by the compiler. For example:

template<class T1, class T2> T1 f(T2){ }
f(1);

The type associated with template parameter T1 cannot be deduced from the function call.


Compiler Error C2784

'declaration' : could not deduce template argument for 'type' from 'type'

The compiler cannot deduce a template argument from the supplied function arguments. For example:

template<class T> class X { };
template<class T> void f(X<T>) {}
f(1);

The compiler cannot deduce what the template argument associated with T is from the above function call. The following code will work:

X<int> x;
f(x);


Compiler Error C2785

'declaration1' and 'declaration2' have different return types

A specialization of a function template differs from the primary function template in return type. For example:

template<class T> void f(T);
template<> int f(int);

Check all specializations of the function template to make sure the return type is consistent.


Compiler Error C2786

'type' : invalid operand for __uuidof

The __uuidof operator can take either a user defined type with a GUID attached or an object of such a user defined type as its argument. This error occurs in the following situations:

  • The argument is not a user defined type;

  • _uuidof cannot extract the GUID from its argument.

For example:

struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) A {
};

void foo(void)
{
    __uuidof(int);      // error C2786
    __uuidof(int *);   // error C2786
    __uuidof(A **);      // error C2786

// no error
    __uuidof(A);
    __uuidof(A *);
    __uuidof(A &);
    __uuidof(A[]);

    int i;
    int *pi;
    A **ppa;

    __uuidof(i);   // error C2786
    __uuidof(pi);   // error C2786
    __uuidof(ppa);   // error C2786
}


Compiler Error C2787

'identifier' : no GUID has been associated with this object

The __uuidof operator can take either a user defined type with a GUID attached or an object of such a user defined type as its argument. This error occurs when the supplied argument is a user defined type, but without a GUID attached.

For example:

struct F {
};

struct __declspec(uuid("00000000-0000-0000-0000-000000000000")) F2 {
};

void bar(void)
{
    __uuidof(F);   // error C2787
    __uuidof(F *);   // error C2787

    __uuidof(F2);   // OK
}


Compiler Error C2788

'identifier' : more than one GUID associated with this object

The __uuidof operator finds more than one GUID associated with the same object.

The example below causes this error:

struct __declspec(uuid("00000001-0000-0000-0000-000000000000")) A { };
struct __declspec(uuid("{00000002-0000-0000-0000-000000000000}")) B { };

template <class T, class U> class Foo { };

typedef Foo<A,B> MyBadFoo;
typedef Foo<A,A> MyGoodFoo;

void bar(void)
{
    __uuidof(MyBadFoo);      // error C2788
    __uuidof(MyGoodFoo);   // OK
}


Compiler Errors C2800 Through C2899

The following topics cover compiler errors C2800 through C2886.


Compiler Error C2800

'operator operator' cannot be overloaded

The specified operator was overloaded.

The following operators cannot be overloaded: class member access operator (.), pointer to member operator (.*), scope resolution operator (::), conditional expression operator (? :), and sizeof operator.

The following is an example of this error:

 class C
 {
    operator:: ();  // error :: is overloaded
 };


Compiler Error C2801

'operator symbol' must be a nonstatic member

The specified overloaded operator was not a member of a class, structure, or union, and/or was declared as static.

The following operators can only be overloaded in class scope as nonstatic members: assignment operator '=', class member access operator '->', subscripting operator '[]', and function call operator '( )'.

The following are examples of this error:

operator[]();            // error, not a member
class A
{
   static operator->();  // error, static
   operator()();         // OK
};


Compiler Error C2802

static member 'operator symbol' has no formal parameters

The specified static member operator had a void formal parameter list.

An operator declared by a static member function must take at least one parameter.

The following is an example of this error:

class A
{
   static operator+ ();     // error, void parameter list
   static operator* ( A& ); // OK
};


Compiler Error C2803

'operator symbol' must have at least one formal parameter of class

The specified overloaded operator was declared without at least one class-type parameter.

The following is an example of this error:

int operator+( int, int );  // error


Compiler Error C2804

binary 'operator operator' has too many parameters

The specified overloaded binary operator was declared with more than one parameter.

The following is an example of this error:

class X
{
   X operator+ ( X , X );  // error, two parameters
   X operator+ ( X );      // OK, one parameter
};


Compiler Error C2805

binary 'operator operator' has too few parameters

The specified binary operator was called with a void parameter list.

The following is an example of this error:

class X
{
public:
   X operator< ( void );  // error, must take one parameter
   X operator< ( X );     // OK
};


Compiler Error C2806

'operator symbol' has too many formal parameters

The specified overloaded operator was declared with too many parameters.

The following is an example of this error:

class X
{
public:
   X operator++ ( int, int ); // error, more than 1 parameter
   X operator++ ( int );      // OK
} ;


Compiler Error C2807

the second formal parameter to postfix 'operator symbol' must be 'int'

The second parameter to the specified postfix operator must be declared to be of type int.

The following is an example of this error:

class X
{
public:
   X operator++ ( X );    // error, nonvoid parameter
   X operator++ ( int );  // OK, int parameter
};


Compiler Error C2808

unary 'operator symbol' has too many formal parameters

The specified overloaded unary operator was incorrectly declared with a nonvoid parameter list.

The following is an example of this error:

class X
{
public:
   X operator! ( X );     // error, nonvoid parameter list
   X operator! ( void );  // OK
};


Compiler Error C2809

'operator symbol' has no formal parameters

The specified operator was incorrectly declared with a void parameter list.

The following is an example of this error:

int operator+ ();  // error


Compiler Error C2810

second formal parameter for 'operator delete' must be 'unsigned int'

An overloaded two-parameter operator delete must have its second formal parameter declared as an unsigned integer.

The second formal parameter in this form of the operator delete specifies the size of the object being deleted. Therefore, it must be of type size_t, that is, an unsigned integer.


Compiler Error C2811

too many formal parameters for based form of 'operator delete'

There were too many formal parameters for the operator delete for based pointers.

When used on based pointers, the operator delete takes either two or three actual parameters.

The following are the prototypes for the based form of the operator delete:

void operator delete( __segment, void __based( void ) * );
operator delete( __segment, void __based( void ) *, unsigned int );


Compiler Error C2812

second formal parameter required for based form of 'operator delete'

There were too few formal parameters for the operator delete for based pointers.

The following are the prototypes for the based forms of the operator delete:

void operator delete( __segment, void __based( void ) * );
operator delete( __segment, void __based( void ) *, unsigned int );


Compiler Error C2813

too many formal parameters for non-based 'operator delete'

Too many formal parameters were provided for the nonbased form of the operator delete. The operator delete can take one or two formal parameters.

The following are the prototypes for the nonbased forms of the operator delete:

void operator delete ( void __near * );
void operator delete ( void __near *, unsigned int );
void operator delete ( void __far * );
void operator delete ( void __far *, unsigned int );
void operator delete ( void __huge * );
void operator delete ( void __huge *, unsigned int );


Compiler Error C2814

second formal parameter for based form of 'operator delete' must be '__based(void) *'

The second formal parameter for an overridden based form of the operator delete must be of type __based(void) *.

The following are the prototypes for the based forms of the operator delete:

void operator delete( __segment, void __based( void ) * );
operator delete( __segment, void __based( void ) *,  unsigned int);


Compiler Error C2815

first actual parameter for based form of 'operator delete' must be '__segment'

The first formal parameter for an overridden based operator delete must be of type __segment.

The following are the prototypes for the based forms of the operator delete:

void operator delete( __segment, void __based( void ) * );
operator delete( __segment, void __based( void ) *,  unsigned int);


Compiler Error C2816

alternative form of 'operator delete' must be a member

The two-parameter form of the operator delete can be redefined only within a class, structure, or union. Global redefinitions of operator delete are allowed to have only one parameter.


Compiler Error C2817

return type for 'operator delete' must be 'void'

A redefinition of the operator delete contained a return statement that returned a type other than void. The return value for the operator delete must be void.


Compiler Error C2818

application of overloaded 'operator ->' is recursive through type 'type'

A redefinition of the class member access operator (->) contained a return statement that was recursive.

To use recursion in a redefinition of the class member access operator, move the recursive routine to a separate function that is called from the operator override function.


Compiler Error C2819

type 'type' does not have an overloaded member 'operator ->'

You need to define an operator->() function in order to use this pointer operation.

The following code illustrates the problem.

class A {
public:
   int i;
};

class B {
};

void C(B j)
{
   j->i; // error C2819
}

To fix this problem, rewrite class B to define an operator->() function.

class B {
   A* pA;

public:

   A* operator->()
   {
      return pA;
   }
};


Compiler Error C2820

second formal parameter required for based form of 'operator new'

There were too few formal parameters for the operator new for based pointers.

This is the prototype for the based form of the operator new:

void __based( void ) * operator new( __segment, unsigned int );


Compiler Error C2821

first formal parameter to 'operator new' must be 'unsigned int'

The first formal parameter of the near or far forms of the operator new must be an unsigned int.

The following are the prototypes for the near and far forms of the operator new:

void __near * operator new( unsigned int );
void __far * operator new( unsigned int );


Compiler Error C2822

second formal parameter for __huge form of 'operator new' must be 'unsigned int'

The second formal parameter of the huge form of the operator new must be an unsigned int.

This is the prototype for the huge form of the operator new:

void __huge * operator new( unsigned long, unsigned int );


Compiler Error C2823

return type for based form of 'operator new' must be 'void __based(void)*'

A redefinition of the based form of the operator new contained a return statement that returned a type that was not a based pointer. The return value for the operator new must be void __based( void ) *.


Compiler Error C2824

return type for 'operator new' must be 'void *'

A redefinition of the nonbased form of the operator new contained a return statement that returned a type that was not a void pointer. The return value for the operator new must be void *.


Compiler Error C2825

first formal parameter for huge form of 'operator new' must be 'unsigned long'

The first formal parameter of the huge form of the operator new must be an unsigned long.

This is the prototype for the huge form of the operator new:

void __huge * operator new( unsigned long, unsigned int );


Compiler Error C2826

second formal parameter required for huge form of 'operator new'

There were too few formal parameters for the operator new for huge objects.

This is the prototype for the huge form of the operator new:

void __huge * operator new( unsigned long, unsigned int );


Compiler Error C2827

'operator symbol' cannot be globally overridden with unary form

The given operator cannot have a unary form outside of an object.

Make sure that the overloaded operator is local to the object or choose an appropriate unary operator to overload.


Compiler Error C2828

'operator symbol' cannot be globally overridden with binary form

The given operator cannot have a binary form outside of an object.

Make sure that the overloaded operator is local to the object or choose an appropriate binary operator to overload.


Compiler Error C2829

'operator symbol' cannot have a variable parameter list

The given operator cannot have a variable parameter list.

The new operator and the function call operator (which is a pair of parentheses — ( )) are the only operators that can take variable parameters.


Compiler Error C2830

only placement parameters to 'operator new' can have default values

The standard formal parameters for the operator new cannot be given default values. Only user-defined placement parameters can specify defaults.

Since the compiler automatically passes values to the standard formal parameters, a default value is meaningless.


Compiler Error C2831

'operator symbol' cannot have default parameters

Default parameters cannot be specified for the given operator.

Only the new, assignment (=), and left parenthesis operators can have default values.


Compiler Error C2832

'modifier' form of 'operator operator' cannot be a member

The specified form of the operator new or delete was declared as a member of a class, structure, or union.

The huge and based forms of these operators are not supported as member functions.

The following are examples of this error:

class T
{
public:
   void __huge* operator new ( unsigned long, size_t );      // error
   void __based(void)* operator new ( __segment, size_t );   // error
   void operator delete ( void __huge* );                    // error
   void operator delete ( __segment, void __based(void)* );  // error
};


Compiler Error C2833

'operator symbol' is not a recognized operator or type

The operator command was not followed by either an operator (to override) or a type (to convert).

Make sure that the operator command is followed by an operator or a type.


Compiler Error C2834

'operator symbol' must be globally qualified

The given operator cannot be local to a class. Since the new and delete operators are tied to the class in which they reside, the scope resolution operator (::) cannot be used to select a version of the operator from a different class.

To implement multiple forms of the new or delete operator, create a version of the operator that takes extra formal parameters.


Compiler Error C2835

user-defined conversion 'type' takes no formal parameters

A user-defined type conversion was declared as having one or more formal parameters. User-defined type conversions cannot take formal parameters.

Remove the formal parameters or choose an operator to overload.


Compiler Error C2836

cannot export 'identifier': a previous declaration did not export it

The given identifier was declared to be exported, but a previous declaration did not export it.

All declarations of a given identifier must be either external or nonexternal.

The following is an example of this error:

extern int i;         // i not exported
int    __declspec(dllexport) i;    // error, i exported


Compiler Error C2837

'identifier' : illegal local static variable in exported inline function

There was an attempt to declare a local static variable inside an external inline function. External inline functions cannot declare local static variables.


Compiler Error C2838

illegal qualified name in member declaration

A member of a different class, structure, or union was declared again, using a fully qualified name, in a second class, structure, or union.

The following is an example of this error:

class Bellini
{
public:
    Norma();
};
class Bottesini
{
    Bellini::Norma();  // error
};


Compiler Error C2839

invalid return type 'type' for overloaded 'operator ->'

An overloaded operator -> did not return a class, struct, or union, or a reference to one.


Compiler Error C2850

#pragma hdrstop cannot be nested in a function or definition

The hdrstop pragma cannot be placed inside the body of a function or definition.

Move the #pragma hdrstop statement to an area that is not contained in curly braces or parentheses.


Compiler Error C2851

#pragma hdrstop required for /Yu command-line option without filename

The /Yu (Use Precompiled Headers) command-line option did not specify the name of a precompiled header file, and there was no #pragma hdrstop statement.

This error can be avoided by specifying a filename after the /Yu command-line option or by using #pragma hdrstop in the source file.


Compiler Error C2852

'file' is not a valid precompiled header file

The specified file is not a precompiled header file. Check that the filename was spelled correctly.


Compiler Error C2853

'file' is not a precompiled header file created with this compiler

The specified precompiled header file was created by a different version of the compiler or by a 32-bit compiler.


Compiler Error C2854

syntax error in #pragma hdrstop

The #pragma hdrstop statement gave an invalid filename.

The hdrstop pragma is followed by an optional filename enclosed in parentheses and quotation marks, as in:

#pragma hdrstop( "source\\pchfiles\\myheader.pch" )

The precompiled header filename cannot be enclosed in angle brackets (<>).


Compiler Error C2855

command-line option 'option' inconsistent with precompiled header

The given command-line option differed from that given when the precompiled header (.PCH) was created.

This error can be avoided by regenerating the precompiled header with the given command-line option.


Compiler Error C2856

#pragma hdrstop cannot be inside an #if block

The hdrstop pragma cannot be placed inside the body of a conditional compilation block.

Move the #pragma hdrstop statement to an area that is not contained in an #if/#endif block.


Compiler Error C2857

'#include' statement specified with the /Ycfilename command-line option was not found in the source file

The /Yc command-line option specified the name of an include file, but that file was not included in the source file being compiled.

Make sure that the filename specified in the /Yc command-line option corresponds to an include file specified in an #include statement in the current source file.

This error can be caused by having the #include statement in a conditional compilation block that is not compiled.


Compiler Error C2858

command-line option '/Yc (/Fdfilename)' inconsistent with precompiled header, which used '/Fdfilename'

The Create Precompiled Header option (/Yc) specified a different program database file than the subsequent Use Precompiled Header option (/Yu).


Compiler Error C2859

filename is not the pdb file that was used when this precompiled header was created, recreate the precompiled header.

Because the compiler shares information between a project's .PDB file and its precompiled header files, you need to make sure both the .PDB and precompiled header files were created together. In the case of this error, recreate the precompiled header.

For more information on creating and using precompiled headers, see /Yc (Create Precompiled Header) and /YX (Automatic Use of Precompiled Headers).


Compiler Error C2860

'void' cannot be an argument type, except for '(void)'

Type void cannot be used as an argument type in an argument declaration list except when it appears by itself, meaning an empty argument list.

The following example shows uses of void as an argument type that cause an error:

void profunc1(void, int i);    // error C2860
void profunc2(int i, void);    // error C2860
void profunc3(int, void);      // error C2860
void profunc4(void, ...);      // error C2860
void profunc5(..., void);      // causes syntax error C2059
void func6(int i, void) {}     // error C2860
void func7(int, void) {}       // error C2860
void func8(void, ...) {}       // error C2860
void func9(..., void) {}       // causes syntax error C2059
void func10(void) {}           // OK


Compiler Error C2867

'identifier' : is not a namespace

This error occurs when a using-directive is applied to something that is not a namespace. For example:

namespace N {
   class X {};
}
using namespace N::X;   //error


Compiler Error C2868

'identifier' : illegal syntax for using-declaration; expected qualified-name

A using-declaration requires a qualified name. Anything else would cause this error to occur. For example:

class X {...};

void f() {
   using X;   //Error
}


Compiler Error C2869

'name' : has already been defined to be a namespace

You tried to use name, and it is already in use as a namespace.

For example, the following code illustrates this error:

namespace A { int i; };

class A { // error C2869, A is already used
};


Compiler Error C2870

'name' : a namespace definition must appear either at file scope or immediately within another namespace definition

You defined namespace name incorrectly. Namespaces should be defined at file scope (outside all blocks and classes, globally) or immediately within another namespace.

For example, the following code shows namespace A defined in function scope (within a function), which is not allowed:

void main(void) {
   namespace A { int i; }; // error C2870

}


Compiler Error C2871

'name' : does not exist or is not a namespace

You did one of the following:

  • You tried to extend an item that is not a namespace.

  • You tried to add a namespace with a using declaration that does not exist.

  • You tried to add a namespace with a using declaration that is not a namespace.

The following code shows all three errors:

int A;
int i;

namespace A { \\ error: cannot extend; A is not a namespace
   using namespace B; \\ error: namespace B does not exist
   using namespace i; \\ error: i is not a namespace
}


Compiler Error C2872

'symbol' : ambiguous symbol

The compiler could not determine which symbol you are referring to.

The following code shows an example of this error.

namespace A {
   int i;
}

using namespace A;

int i;

void z() {
   ::i++;   // ok
   A::i++;   // ok
   i++;      // error C2872, ::i or A::i?
}


Compiler Error C2873

'symbol' : symbol cannot be used in a using-declaration

This error can be caused by a missing namespace keyword in a using-directive. This can cause the compiler to misinterpret the code as a using-declaration rather than a using-directive. See using Directive and using Declaration for more information.


Compiler Error C2874

using-declaration causes a multiple declaration of 'symbol'

Your using-declaration is incorrect because it would cause the same item to be defined twice.

For example, the following code shows an incorrect using declaration.

namespace Z {
   int i;
}

void a() {
   int i;
   using Z::i; // error C2874, i already declared
}


Compiler Error C2875

using-declaration causes a multiple declaration of 'class::identifier'

Your using-declaration is incorrect because it would cause the same item to be defined twice.

For example, the following code shows an incorrect using declaration.

class A {
public:
   int z;
};

class B : public A {
   using A::z;
   using A::z; // C2875, A::z defined more than once
};


Compiler Error C2876

'class::symbol' : not all overloads are accessible

All overloaded functions derived from a base class must be accessible in the derived class.

For example, in the following code, the int version of overloaded function a is not accessible in the derived class B.

class A {
public:
   double a(double);
private:
   int a(int);
};

class B : public A {
   using A::a; // error C2876
};


Compiler Error C2877

'class::symbol' : is not accessible

All members derived from a base class must be accessible in the derived class.

For example, in the following code, the variable a is not accessible in the derived class B.

class A {
private:
   int a;
};

class B : public A {
   using A::a; // error C2877
};


Compiler Error C2878

'name' : a namespace or class of this name does not exist

You made reference to a namespace or class that is not defined.

For example, the following code shows namespace B defined as an alias for namespace C, but namespace C does not exist. The code will compile if you use namespace A instead of namespace C.

namespace A {}

namespace B = C;   // error C2878, namespace C doesn't exist


Compiler Error C2879

'symbol' : symbol can not be aliased

You tried to create a namespace alias to a symbol that is not a namespace.

The following code shows the problem:

int i;

namespace A = i; // error C2879, i is not a namespace


Compiler Error C2880

'symbol' : a symbol of this name already exists in the current scope

You tried to create a namespace alias, but the name you chose already exists.

The following code shows the problem. Since i is already defined as an integer, it cannot be reassigned as a namespace alias.

namespace A {
   int k;
}

int i;

namespace i = A; // error C2880, i already exists


Compiler Error C2881

'namespace1' : is already used as an alias for 'namespace2'

You tried to use a namespace as an alias, but it is already in use as an alias to another namespace.

For example, the following code uses namespace C as an alias for both namespace A and namespace B.

namespace A {
   int k;
}

namespace B {
   int i;
}

namespace C = A;
namespace C = B; // C2881, C is already an alias for A


Compiler Error C2882

'name' : illegal use of namespace identifier in expression

You tried to use the name of a namespace in an expression.

In the following code, namespace A is assigned to integer i, an incorrect use of namespace A.

namespace A {
   int k;
}

int i = A; // error C2882, can't assign A to i


Compiler Error C2883

'name' : local function declaration conflicts with 'identifier' introduced by using-declaration

You tried to define a function more than once. The first definition was made from a namespace with a using declaration, and the second was a local definition.

namespace A {
   void z(int);
}

void f() {
   using A::z;
   void z(int); // error C2883, z is already defined
}


Compiler Error C2884

'name' : introduced by using-declaration conflicts with local function 'function'

You tried to define a function more than once. The first definition was a local definition, and the second was made from a namespace with a using declaration.

namespace A {
   void z(int);
}

void f() {
   void z(int);
   using A::z; // error C2884, z is already defined
}


Compiler Error C2885

'class::identifier' : a using-declaration as a member of a class must be a member-declaration

You used a using declaration incorrectly. If you use the using keyword with a class member, C++ requires you to define that member inside another class (a derived class).

The following example shows the error:

class A {
public:
   int i;
};

void z() {
   using A::i; // error C2885, not member declaration
}


Compiler Error C2886

'class::identifier' : symbol cannot be used in a member using-declaration

You used a symbol such a namespace name in a using declaration. Using declarations are for declaring base class members.

The following example shows this error:

namespace Z {
   int i;
}

class A {
   using Z::i; // error c2886, Z::i is a namespace
};


Compiler Error C2888

'identifier' : symbol cannot be defined within namespace 'namespace'

A symbol belonging to namespace A must be defined in a namespace that encloses the namespace A. Otherwise, an error is generated.

The following is an example:

namspace M {
   namespace N {
      void f1();
      void f2();
   }
   void N::f1() {...   //OK: namspace M encloses N
   }
}

namespace O {
   //Error: namespace O does not enclose M
   void M::N::f2(){...
   }
}


Compiler Error C2891

'identifier' : cannot take the address of a template parameter

A template parameter is not a real variable so you cannot take its address.

An example of how of this error message would be to define a template in a global namespace:

template<int n>
class X {
public:
   void mf() {
      int *pI = &n;   // Error: cannot take the address of a template parameter
   }
};

and then call the mf function:

X<10> x;
x.mf();


Compiler Error C2894

templates cannot be declared to have 'C' linkage

Templates cannot be declared with “C” linkage. This error is generated when a template is defined inside an extern “C” block. For example:

extern “C” {
   template<class T> class stack {   //error
   };
   template<class T> void f(const T &aT){} //error
}

and

extern “C” template<class T> void f(const T &aT) {} //error


Compiler Error C2895

'function' : cannot explicitly instantiate a function template that has been declared with dllimport

The compiler cannot explicitly instantiate a function template that has been declared with the dllimport extended attribute. For example:

template<class T> void mf(T) {...
};
template void __declspec(dllimport) mf<int>(int); //error

The following code would work if the function can be inlined, otherwise the function in the DLL will be called and the error will be generated.

template<class T> void mf(T) {...
}
inline template void __declspec(dllimport) mf<int>(int);


Compiler Error C2896

'function1' : cannot use function template 'function2' as argument

A function template cannot be used as an argument to another function template. For example:

template<class T1, class T2> void f1(void(*)(T1, T2));
template<class T1, class T2> void f2(T1, T2);

void g() {
   f1(f2);
}


Compiler Error C2897

'Declaration' : destructors cannot be templates

You cannot declare a destructor as a template. This is because destructors of a normal class cannot be overloaded. Defining a destructor as a template is the same as defining a set of destructors. Therefore, it is illegal. For example,

class X {
public:
   template<typename T> ~X() {...} //Error
};


Compiler Error C2898

'Declaration' : member function templates cannot be virtual

Member function templates cannot be virtual. For example:

class X {
public:

   //Error:
   template<typename T> virtual void f(T t){...}
};


Compiler Error C2899

typename cannot be used outside a template declaration

The typename keyword can only be used in a template definition or declaration. In a template declaration, it can be used in two ways. See the example below:

// one way to use typename
template<typename T> class X {};

// another way to use typename
template<class T> struct X {
   typename T::A a;   // T::A is a type
};

If typename is used outside a template declaration, this error will be generated. For example:

struct Y {
   typedef int B;
   typename Y::B b;   //illegal
};


Compiler Errors C2900 Through C2999

The following topics cover compiler errors C2900 through C2999.


Compiler Error C2901

'declaration1' : function differs from 'declaration2' only by return type or calling convention

A specialization of a function template differs from the primary function template in return type or calling convention.

The following code will generate this error:

template<class T> void __cdecl f(T);
template<> void __stdcall f(int);

Note This error is active only when the /Za compiler optioin (Disable Language Extensions) is specified.


Compiler Error C2902

'%$L' : unexpected token following 'template', identifier expected

An identifier is expected to follow the keyword template, but something else is seen instead. For example:

namespace N {
   template<class T> class X {};
   class Y {};
}
void f() {
   N::template X<int> x1; // legal
}
void g() {
   N::template + 1; // this generates error C2902
}


Compiler Error C2903

'identifier' : symbol is neither a class template nor a function template

An attempt to force the explicit instantiation of something that is not a template generates this error. For example:

namespace N {
   template<class T> class X {};
   class Y {};
}
void g() {
   N::template Y y; // this generates error C2903
}


Compiler Error C2904

'identifier' : template-name already defined as 'declaration'

The template name has been defined elsewhere. Check the code for duplicate names.

The following code will generate this error:

void X(); // X is declared as a function
template<class T> class X{}; // X is used again


Compiler Error C2906

C++ language change: to explicitly specialize class template 'identifier' use the following syntax -

This is the new syntax for the explicit specialization of templates. For example:

template<class T> class X{};   // primary template
class X<int> { }         // old way -- now illegal
template<> class X<int> { };   // new way

Note This error is active only when the /Za compiler option is specified.


Compiler Error C2907

explicit specialization; 'declaration' is not a member of a class template

This error is caused by an attempt at explicit specialization of a static data member of a non-template class. For example:

class X {
   static int data;
};

template<> int X::data=0;

The above code will generate this error.


Compiler Error C2908

explicit specialization; 'template' has already been specialized from the primary template

This error occurs when a specialization of the primary template has been generated before the compiler encounters an explicit specialization. For example:

template<class T> class X {};

void f() {
X<int> x;      //specialization and instantiation
         //of X<int>
}

template<> class X<int> {}   //explicit specialization

This code will generate the error.


Compiler Error C2909

'identifier': explicit instantiation of template function requires return type

An explicit instantiation of a function template requires its return type to be explicitly specified. Implicit return type specification will not work. For example:

template<class T> int f(T);
template f<int>(int);   //illegal -- causes the error to occur
template int f<int>(int);   // legal


Compiler Error C2912

explicit specialization; 'declaration' is not a function template

An attempt to explicitly specialize a function that is not a function template causes this error. For example:

void f();
template<> void f<char>(char);


Compiler Error C2913

explicit specialization; 'declaration' is not a class template

An attempt to explicitly specialize a class that is not a class template causes this error. For example:

class X{};
template<> class X<int> {};


Compiler Error C2914

'identifier' : cannot deduce template argument as function argument is ambiguous

An attempt to deduce a template argument from an overloaded function has led to ambiguity. The compiler cannot determine which of the overloaded functions to use.

The following code will generate this error:

void f(int);
void f(double);

template<class T> void g(void (*) (T));

void h() { g(f); }


Compiler Error C2917

'name' : invalid template-parameter

A template parameter list containes an identifier that was not a template parameter.

The following code will generate this error:

template<class T> class Vector { void sort(); };

template<class T> void Vector<C>::sort() // error: 'C'
{
}


Compiler Error C2918

'name' : illegal use of local type in template instantiation

There was an attempt to generate a template function (that is, a function generated from a function template) based on a local type. A template can be instantiated only using a type with external linkage.

The following code will generate this error:

template<class T> void f(T t) {};

void g()
{
    struct X {};
    X x;

    f(x);          // error
}


Compiler Error C2919

illegal use of anonymous local type in template instantiation

There was an attempt to generate a template function (that is, a function generated from a function template) based on a local type. A template can be instantiated only using a type with external linkage.

The following code will generate this error:

template<class T> void f(T t) {};

void g()
{
    struct {} x;

    f(x);         // error
}


Compiler Error C2920

redefinition : 'class' : template class has already been declared as 'identifier'

There is more than one declaration of class, and the declarations are not equivalent.


Compiler Error C2921

redefinition : 'class' : template class is being redeclared as 'identifier'

There is more than one declaration of class, and the declarations are not equivalent.


Compiler Error C2922

'symbol' : a friend function of a template class must have been previously declared

A class declaration included a reference to a friend function that was not defined. Make sure that a prototype for this function appears before the class declaration, such as in an include file.


Compiler Error C2923

'type' : 'identifier' is invalid as template argument 'number', type expected

A type was needed for argument number when instantiating a template. Check the template declaration for the proper parameter types.


Compiler Error C2924

'identifier' : explicit instantiation; name is not a member of a template-class specialization

There was an attempt to explicitly instantiate the given identifier, which is not a templated class. The following code generates this error:

template int NotAClass;  // error


Compiler Error C2925

'identifier' : explicit instantiation; class 'member' does not specify a template-class specialization

There was an attempt to explicitly instantiate a member of a class that was not templated. The following code generates this error:

class C
{
   public: void a(void){};
};
template C::a(void);  // error


Compiler Error C2926

'type' : types with no linkage cannot be used as template arguments

There was an attempt to generate a template class (that is, a class generated from a class template) based on a local type. A template can be instantiated only using a type with external linkage.

The following code will generate this error:

template<class T> class X{};

void f()
{
    struct Y{};

    X<Y> x;         // error
}


Compiler Error C2927

'function' : a template function must be called with at least one argument

An attempt was made to call a template function without any arguments. When a template function is called, the type of the argument determines which version of the function is actually generated; without an argument, no function can be generated.


Compiler Error C2928

explicit instantiation; 'identifier' is not a function or static data member of template-class 'class'

There was an attempt to explicitly instantiate a member of class that was not a function or static variable. Only member functions and static data can be explicitly instantiated.


Compiler Error C2929

'identifier' : explicit instantiation; cannot explicitly force and suppress instantiation of template-class member

There was an attempt to explicitly instantiate identifier as well as prevent it from being instantiated. The following code generates this error:

template A<int>::A();
extern template A<int>::A();  // error


Compiler Error C2930

'class' : template-class-id redefined as an enumerate of 'enum identifier'

There was an attempt to use the templated class as a member of the enumeration identifier. Make sure that the curly braces ({}) in this area are properly matched.


Compiler Error C2931

'class' : template-class-id redefined as a member function of 'identifier'

There was an attempt to use the templated class as a member function of the class identifier. Make sure that the curly braces ({}) in this area are properly matched.


Compiler Error C2932

'class' : template-class-id redefined as a data member of 'identifier'

There was an attempt to use the templated class as a data member of identifier.


Compiler Error C2933

'class' : template-class-id redefined as a typedef member of 'identifier'

There was an attempt to use the templated class as a typedef of identifier.


Compiler Error C2934

'class' : template-class-id redefined as a nested 'item' of 'identifier'

There was an attempt to use the templated class in a nested item.


Compiler Error C2935

'class' : template-class-id redefined as a global function

There was an attempt to use the templated class as a global function. Make sure that the curly braces ({}) in this area are properly matched.


Compiler Error C2936

'class' : template-class-id redefined as a global data variable

There was an attempt to use the templated class as a global data variable. Make sure that the curly braces ({}) in this area are properly matched.


Compiler Error C2937

'class' : template-class-id redefined as a global typedef

There was an attempt to use the templated class as a global typedef.


Compiler Error C2938

'class' : template-class-id redefined as a global 'item'

There was an attempt to use the templated class as an item.


Compiler Error C2939

'class' : template-class-id redefined as a local data variable

There was an attempt to use the templated class as a local data variable. Make sure that the curly braces ({}) in this area are properly matched.


Compiler Error C2940

'class' : template-class-id redefined as a local typedef

There was an attempt to use the templated class as a local typedef.


Compiler Error C2941

'class' : template-class-id redefined as a local 'item'

There was an attempt to use the templated class as an item.


Compiler Error C2942

'class' : template-class-id redefined as a formal argument of a function

There was an attempt to use the templated class as a formal argument. You cannot pass an argument directly to the constructor of a templated class.


Compiler Error C2943

'class' : template-class-id redefined as a type argument of a template

There was an attempt to use the templated class as a type argument for a template. Use a symbol to take the type argument of a template.

The following example causes this error:

template<class T> class List {};
template<class List<int> > class MyList;   // error


Compiler Error C2944

'class' : template-class-id redefined as a value argument of a template

There was an attempt to use the templated class as a value argument for a template. Use a symbol to take the value argument of a template.


Compiler Error C2945

explicit instantiation does not refer to a template-class specialization

There was an attempt to explicitly instantiate something that was not templated.


Compiler Error C2946

explicit instantiation; 'class' is not a template-class specialization

There was an attempt to explicitly instantiate a class that was not templated. The following code generates this error:

class C {};
template C;  // error


Compiler Error C2947

'identifier' : cannot specialize a template-class with a reference to a local-extern

A template specialization was made with the address of a variable or function whose first declaration occurs in a local extern context.

The following is an example of this error:

template<int* p> class X {};
void func ()
{
    extern int i;
    X<&i> object;   // error emitted here
}


Compiler Error C2948

explicit instantiation; storage class specifier 'specifier' not permitted on specialization

You cannot use storage-class specifiers, such as extern, in a specialization of a template class that was previously explicitly instantiated.


Compiler Error C2949

'symbol' : explicit instantiation; cannot use 'auto' and 'extern' on the same template-class specialization

A template class was instantiated more than once, once using the extern storage-class specifier and once without.

If you must duplicate an instantiation of a template class, make sure that you use the same storage-class specifier for each declaration.

The following code generates this error:

template <class T> class X {};
extern template X<int>;
template X<int>;   // error


Compiler Error C2950

'symbol' : invalid left delimiter in template declaration : expected '<'

The given symbol was used after the template keyword. This can be caused by an improperly expanded macro. The following code generates this error:

template <<class T> class D{};  // error


Compiler Error C2951

template declarations are only permitted at global or namespace scope

You cannot declare a template outside global or namespace scope. If you make your template declarations in an include file, make sure that the include file is at global scope. The following code generates this error:

void main()
{
   template <class T> class A {};  // error
}


Compiler Error C2952

template declaration must specify parameter list

There was an attempt to declare a template without specifying a parameter list. A template declaration is meaningless unless it has a parameter list consisting of one or more types.

The following code generates this error:

template<> class C {};  // error
template<class T> class D {};  // okay


Compiler Error C2953

'identifier' : template class has already been defined

The template class identifier has been previously defined in this module. Check this source file and any included files for other definitions. The following code generates this error:

template <class T> class A    {};
template <class T> class A    {};  // error


Compiler Error C2954

template definitions cannot nest

Nested template declarations are not allowed. This error can be caused by improperly matched curly braces ({}).


Compiler Error C2955

'identifier' : use of class template requires template argument list

A class template was used as an identifier without a template argument list. Add a valid template argument list to solve this problem.

The following example will generate the error:

template<class T> class X {};
X x;      // C2955


Compiler Error C2956

'<' : unexpected for non-template class 'identifier'; ignoring template argument list

There was an attempt to instantiate a non-templated class. Make sure that you are using angle brackets with the correct class. The following code will generate this error:

class c{};
c<int> MyClass;  // error


Compiler Error C2957

'symbol' : invalid left delimiter for template class 'identifier' : expected '<'

The specified symbol was used instead of an opening angle bracket (<) when referring to a templated class. This can be caused by an improperly expanded macro. The following code generates this error:

template <class T> class c {};
c <<int> Instantiation1;  // error


Compiler Error C2958

the left delimiter found at 'location' was not matched correctly

The specified delimiter could not be matched. For example, a mismatched parenthesis in a function template declaration would generate this error.


Compiler Error C2959

'identifier' : an 'enum' may not be declared as a template

The specified identifier was declared as an enum type preceded by the template keyword. Only the class, struct, and union specifiers can be used when declaring a templated class. The following code will generate this error:

template <class T> enum E{};  //error


Compiler Error C2960

template 'identifier' requires a tag-name

The template class specified by the identifier is followed by a union, struct, class, or enum without its own identifier.

template <class T> class D struct;


Compiler Error C2961

syntax error : 'item' : unexpected token in template declaration

Item caused a syntax error in a template declaration. This error can be caused by mismatched delimiters.


Compiler Error C2962

syntax error : 'item' : expected template-class member function definition to end with '}'

Item caused a syntax error in a template definition. This error can be caused by mismatched delimiters.


Compiler Error C2963

string literals are not permitted as parameter to a template specialization

One or more of the template parameter expressions was a string literal, which is not valid as a template parameter. You may be able to work around this problem by using a pointer to a string variable.


Compiler Error C2964

invalid expression as template parameter

One or more of the template parameter expressions was not valid as a template parameter. Check the template declaration for parameter types.

The following is an example of this error:

class C {};
template<class T, C c> class MyClass {};
template MyStack< int, 4 >;  // error


Compiler Error C2965

'identifier' : invalid overloading of static data member for template class 'class'

There was an attempt to overload the identifier, which is already defined as static data.


Compiler Error C2966

'identifier' : adding member function of same name as existing static data member for template class 'class'

There was a naming conflict between a static data member and a function member called identifier of the templated class class. These items cannot have the same name.


Compiler Error C2967

'identifier' : adding static data member of same name as existing member function for template class 'class'

There was a naming conflict between a static data member and a function member called identifier of the templated class class. These items cannot have the same name.


Compiler Error C2968

'identifier' : user specialization of template class has an incomplete definition : expected '}' but found 'symbol'

When attempting to generate a user specialization of a template class, the compiler was unable to match braces around the templated class. Check the template definition for matching curly braces ({}).


Compiler Error C2969

syntax error : 'symbol' : expected member function definition to end with '}'

There was an unmatched closing brace (}) in a template member function definition. Check the area for matched delimiters.


Compiler Error C2970

'class' : template argument '#number' : invalid address of static variable 'identifier'

There was an attempt to use the address of a static variable as a template argument. You cannot take the address of a static variable.


Compiler Error C2971

'class' : template argument '#number' : invalid address of local variable 'identifier'

There was an attempt to use the address of a local variable as a template argument. You cannot take the address of a local variable.


Compiler Error C2972

'class' : template argument 'number' : 'item' is not a valid template argument

There was an attempt to use item as a template argument.


Compiler Error C2973

invalid template argument '#number'

This template argument is invalid. Check the template definition for the correct types accepted when creating a template specialization.


Compiler Error C2974

invalid template argument 'number', type expected

The template argument did not match the template declaration; a type was expected within the angle brackets. Check the template declaration to find the correct template parameters.


Compiler Error C2975

invalid template argument 'number', constant expression expected

The template argument did not match the template declaration; a constant expression was expected within the angle brackets. Variables are not allowed as template actual arguments. Check the template declaration to find the correct template parameters.


Compiler Error C2976

'identifier' : too few template arguments

The template named identifier was missing one or more actual arguments. Check the template declaration to find the correct number of template parameters. This error message may be caused by missing template arguments in STL components.


Compiler Error C2977

'identifier' : too many template arguments

The template named identifier had too many actual arguments. Check the template declaration to find the correct number of template parameters.

The following is an example of this error:

template<class T, int i> class MyClass {};
template MyClass< int , 1, 1 >;  // error


Compiler Error C2980

unexpected token in template declaration

The template declaration has a syntax error.


Compiler Error C2981

one or more missing '>' in template declaration

The compiler could not find a closing brace (>) for the template declaration. This can be caused by an expression with an ambiguous right-shift operator or an improperly expanded macro. The following code generates this error:

template <class T>> class D{};  // error


Compiler Error C2982

'identifier' : new template parameter list has less parameters than the previous declaration

The list of template arguments did not match that of the previous declaration.


Compiler Error C2983

'identifier' : new template parameter list has more parameters than the previous declaration

The list of template arguments did not match that of the previous declaration.


Compiler Error C2984

'identifier' : template parameters 'argument1' and 'argument2' do not match

The list of template arguments did not match that of the previous declaration.


Compiler Error C2985

'identifier' : invalid static data member; template class 'class' already has a function member of the same name

There was a naming conflict between a static data member and a function member called identifier of the templated class class. These items cannot have the same name.


Compiler Error C2986

'identifier' : invalid function member; template class 'class' already has a static data member of the same name

There was a naming conflict between a static data member and a function member called identifier of the templated class class. These items cannot have the same name.


Compiler Error C2987

'identifier' : redefinition type mismatch for static data member of template class 'class'

There was a type conflict between two static data members. You cannot use non-equivalent types when multiply defining a static variable.


Compiler Error C2988

unrecognizable template declaration/definition

The template declaration cannot be parsed correctly. Make sure that you have the correct delimiters in the right places.


Compiler Error C2989

'class' : template class has already been defined as a non-template class

The given class was previously defined as a non-template class. Check header files to make sure that there are no conflicts. The following code generates this error:

class C{};
template <class T> class C{};  // error


Compiler Error C2990

'class' : non-template class has already been defined as a template class

The given class was previously defined as a template class. Check header files to make sure that there are no conflicts. The following code generates this error:

template <class T> class C{};  // error
class C{};


Compiler Error C2991

redefinition of template parameter 'parameter'

There was a type conflict between two template definitions of parameter. You cannot use non-equivalent types when multiply defining a template parameter.


Compiler Error C2992

'identifier' : invalid or missing template parameter list

The class specified by identifier is preceded by a template keyword with no parameters. The following code generates this error:

template<> class A {};  // error


Compiler Error C2993

'identifier' : template parameter can never be initialized

There was an attempt to declare a structure or union argument to a template. The structure or union cannot be initialized. Use pointers to pass structures and unions as template parameters. The following code generates this error:

struct MyStruct {
   int a;char b;
};
template <class T, struct MyStruct S> {};  // error


Compiler Error C2994

unnamed class in template parameter list

There was an attempt to use a class as a template parameter, but none was named. This error can be caused by using the class keyword without specifying a class name.


Compiler Error C2995

'identifier' : template function has already been defined

The template function identifier has been previously defined. Make sure that there is only one member function definition for each member function of a templated class.


Compiler Error C2996

'identifier' : recursive template function definition

The function definition specified by identifier attempts to instantiate its root templated class. Recursive template instantiations are not allowed.


Compiler Error C2997

'identifier' : function parameter list must use template parameter 'parameter'

In templated functions, all template parameters must be used as parameters for the function. The following code generates this error:

template <class T> int max(int x, int y)  // error: T not used
   {return (x>y)?x:y;}


Compiler Error C2998

'identifier' : is not a valid name for a template definition

The template definition used an ununderstandable syntax. The following code generates this error:

template <class T> int x = 1018;


Compiler Error C2999

UNKNOWN ERROR
From the Help menu choose the Technical Support command
or open the technical-support help file for more information

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in your documentation.


Compiler Warnings C4001 Through C4099

The following topics cover compiler warnings C4001 through C4099.


Compiler Warning (level 4) C4001

nonstandard extension 'single line comment' was used

A single-line comment, which is a Microsoft extension to C (but standard in C++), was used in a C source file.

If the /Za (disable Microsoft extensions) option has been specified, this condition generates a syntax error.

To disable this warning, insert #pragma warning(disable:4001) into your code. See #pragma warning in the Preprocessor Reference for more information.

The following is an example of this warning:

int i;    // warning
int j;    /* no warning */


Compiler Warning (level 1) C4002

too many actual parameters for macro 'identifier'

The number of actual parameters specified with the given identifier was greater than the number of formal parameters given in the macro definition of the identifier.

The additional actual parameters were collected but ignored during expansion of the macro.


Compiler Warning (level 1) C4003

not enough actual parameters for macro 'identifier'

The number of actual parameters specified with the given identifier was less than the number of formal parameters given in the macro definition of the identifier.

When a formal parameter is referenced in the definition and the corresponding actual parameter has not been provided, empty text is substituted in the macro expansion.


Compiler Warning (level 1) C4004

incorrect construction after 'defined'

The defined operator was incorrectly terminated, causing a warning or error to appear when the remainder of the line following defined was compiled.

The following example generates this warning and a fatal error:

#if defined( ID1 ) || ( ID2 )

The compiler assumed that the identifier ID1 was the only operand for the defined operator. The rest of the line could not be parsed.

The following avoids this problem:

#if defined( ID1 ) || defined( ID2 )


Compiler Warning (level 1) C4005

'identifier' : macro redefinition

The given identifier was defined twice. The compiler used the second macro definition.

This warning can be caused by defining a macro on the command line and in the code with a #define directive. It also can be caused by macros imported from include files.

To eliminate the warning, either remove one of the definitions or use an #undef directive before the second definition.


Compiler Warning (level 1) C4006

#undef expected an identifier

The name of the identifier whose definition was to be removed was not given with the #undef directive. The #undef directive was ignored.


Compiler Warning (level 2) C4007

'identifier' : must be 'attribute'

The attribute of the given function was not explicitly stated. The compiler forced the attribute.

For example, the function main must have the __cdecl attribute.


Compiler Warning (levels 2 and 3) C4008

'identifier' : 'identifier' attribute ignored

The __fastcall, static, or inline attribute for the given identifier was ignored.

Data cannot be defined with the __fastcall attribute, and the main function cannot be defined with the static or inline attribute.

This is a level 2 warning for data and a level 3 warning for functions.


Compiler Warning (level 1) C4009

string too big; trailing characters truncated

A string exceeded the compiler limit of 2047 characters on string size. The excess characters at the end of the string were truncated.

To correct this problem, break the string into two or more strings.


Compiler Warning (level 3) C4010

single-line comment contains line-continuation character

A single-line comment (introduced by //) contains a line-continuation character (\). The next line after the line-continuation character is ignored; it is considered to be the continuation of the previous line and is treated as a comment.

For performance reasons, some syntax-directed editors will not correctly indicate the physical line following the line-continuation character as a comment. You should ignore the syntax coloring on any lines that cause this warning.


Compiler Warning (level 1) C4011

'identifier' : identifier was truncated to 'number' characters

The name of the specified identifier was too long.

The maximum length of a linkable external identifier is 247 characters, after name decoration.

The default maximum length of an undecorated name or user-entered fragment of a decorated name is 32 characters. The /H compiler switch can be used to set a different maximum length.


Compiler Warning (level 1) C4012

float constant in a cross compilation

You receive this message once if you use floating point constants when using a cross compiler since floating point constants are not stored the same on different computer architectures.


Compiler Warning (level 3) C4013

'function' undefined; assuming extern returning int

An undefined function was called. The compiler assumed an external function that returned an int type.

Make sure that the function name is spelled correctly. All external functions should be prototyped as extern.


Compiler Warning (level 1) C4014

concatenating mismatched wide strings

A wide string literal was concatenated with a standard string literal.

Make sure that all wide string literals are prefixed with an "L" character, as in:

char   hello[] = L"Hello, " "world"   // Warning
char   hello[] = L"Hello, " L"world"  // OK


Compiler Warning (level 1) C4015

'identifier' : type of bit field must be integral

The given bit field was not declared as an integral type. The compiler assumed the base type of the bit field to be unsigned.

Bit fields must be declared as unsigned integral types.


Compiler Warning (level 3) C4016

'function' : no function return type; using int as default

Since the given function had not yet been declared or defined, the return type was unknown. A default return type of int was assumed.

This warning may be avoided by adding a prototype for the given function.


Compiler Warning (level 3) C4018

'expression' : signed/unsigned mismatch

There was an attempt to compare a signed and unsigned number. The signed value was converted to an unsigned type for the comparison.

When performing an equal (= =) or not equal (!=) comparison between signed and unsigned types, cast one type to the other to ensure proper comparison.


Compiler Warning (level 4) C4019

empty statement at global scope

The compiler found a semicolon that was not preceded by a statement. This warning is generated only at global scope.

This warning can be avoided by removing the extra semicolon.

The following example demonstrates this warning:

#define declint( varname ) int #varname;
declint( a );         //Warning, int a;;
declint( b )          //OK, int b;


Compiler Warning (level 1) C4020

'function' : too many actual parameters

The number of actual parameters specified in a function call was greater than the number of formal parameters specified in the function prototype or function definition.

The extra actual parameters were passed according to the calling convention used on the function.


Compiler Warning (level 1) C4021

'function' : too few actual parameters

The number of actual parameters specified in a function call was less than the number of formal parameters specified in the function prototype or function definition.

Only the provided actual parameters were passed. If the called function references a variable that was not passed, the results are undefined.


Compiler Warning (level 1) C4022

'function' : pointer mismatch for actual parameter 'number'

The pointer type of the given actual parameter was different from the pointer type specified in the formal parameter list or function definition.

The actual parameter was passed without change. Its value will be interpreted as a pointer within the called function.


Compiler Warning (level 3) C4023

'symbol' : based pointer passed to unprototyped function : parameter number

If you pass a based pointer to a unprototyped function, the pointer is normalized, which could cause unpredictable results. You should prototype functions that are passed based pointers.


Compiler Warning (level 1) C4024

'function' : different types for formal and actual parameter 'number'

You called function with parameter number different from the function declaration. For instance, if you prototype a function with a char * and call it with an int, you’ll get this message.

The actual parameter will be passed without change, and the function will convert the parameter's type to the type expected by the function.

Here is an example of code that causes the warning:

void func(char *var);

void main() {

    func(5);  // warning 4024, func called with int
}


Compiler Warning (level 1) C4025

'number' : based pointer passed to function with variable arguments: parameter number

If you pass a based pointer to a function with variable arguments, the pointer is normalized, which could cause unpredictable results. You should not pass based pointers to functions with variable arguments.


Compiler Warning (level 1) C4026

function declared with formal parameter list

The function was declared to take formal parameters, but the function definition did not have formal parameters.

Subsequent calls to this function will assume that the function takes no actual parameters.


Compiler Warning (level 1) C4027

function declared without formal parameter list

The function was declared to take no formal parameters (the formal parameter type list consisted of the keyword void), but either formal parameters were given in the function definition or actual parameters were given in a call to the function.

Subsequent calls to this function will assume that the function takes actual parameters of the types found in the function declaration or call.


Compiler Warning (level 1) C4028

formal parameter 'number' different from declaration

The type of the given formal parameter did not agree with the corresponding parameter in the declaration or definition.

The type in the original declaration was used.


Compiler Warning (level 1) C4029

declared formal parameter list different from definition

The types of formal parameters given in the function declaration did not agree with the types of the formal parameters given in the function definition.

The formal parameter list of the definition was used.


Compiler Warning (level 1) C4030

first formal parameter list longer than the second list

A function was declared more than once with different formal parameters.

The formal parameters given in the first declaration were used.


Compiler Warning (level 1) C4031

second formal parameter list longer than the first list

A function was declared more than once with different formal parameters.

The formal parameters given in the first declaration were used.


Compiler Warning (level 4) C4032

formal parameter 'number' has different type when promoted

The type of the specified parameter is not compatible through default promotions with the type in a previous declaration.

For two function types to be compatible, the type of each parameter must be compatible with the type that results from application of the default argument promotion.

This is an error in ANSI C (/Za) and a warning when the Microsoft extensions (/Ze) are used.

The following example causes this warning:

void func();
void func(char);     // warning, char promotes to int


Compiler Warning (level 1) C4033

'function' must return a value

The given function did not return a value.

Only functions with a return type of void can use the return command without an accompanying return value.

An undefined value will be returned when this function is called.


Compiler Warning (level 1) C4034

sizeof returns 0

The sizeof operator was applied to an operand that yielded a size of zero.

This warning indicates that the operand of the sizeof operator was an empty structure, union, class, or enumerated type, or was of type void.


Compiler Warning (level 3) C4035

'function' : no return value

A function did not include a return statement.

This warning is generated for all functions (including main) that do not have return statements. Functions with a return type of void will not generate this warning.

An undefined value will be returned when this function is called.


Compiler Warning (level 1) C4036

unnamed 'type' as actual parameter

The type of the structure, union, enumerated type, or class being passed as an actual parameter was not given.

The formal parameter in the generated function prototype will be commented out.

This warning occurs only when using the /Zg option for generating function prototypes and can be avoided by providing the appropriate type explicitly.


Compiler Warning (level 1) C4037

conflicting ambient class modifiers

More than one ambient class modifier was specified for a class, structure, or union.

Only one ambient class modifier can be specified for a class, structure, or union.


Compiler Warning (level 1) C4038

'modifier' : illegal ambient class modifier

The specified modifier cannot be used for a class declared with dllimport or dllexport attributes.


Compiler Warning (level 1) C4041

compiler limit : terminating browser output

The limit to browser information has been exceeded. If you compiled using the /FR option (for source browser information including local variables), recompile using the /Fr option (for source browser information without local variables). Otherwise, disable the browser output option.


Compiler Warning (level 1) C4042

'identifier' : has bad storage class

The storage class specified for the identifier could not be used in this context.

A default storage class for this context was used in place of the illegal storage class. Only the register storage class can be specified in a parameter declaration. The storage class was selected using the following rules.

  • If the identifier was a function, the compiler assumed extern class.

  • If the identifier was a formal parameter or local variable, the compiler assumed auto class.

  • If the identifier was a global variable, the compiler assumed the variable was declared with no storage class.


Compiler Warning (level 1) C4043

function specifier used more than once

A function specifier was used more than once for a symbol.

The second function specifier was ignored.

The following example generates this warning:

inline inline void  no_op( void ) { };


Compiler Warning (level 1) C4044

specifier __huge on 'identifier' ignored; can only be applied to array

The compiler ignored the __huge memory attribute for the given identifier. Only arrays can be declared with the __huge memory attribute. For pointers, __huge must be used as a modifier, not as a memory attribute.


Compiler Warning (level 1) C4045

'identifier' : array bounds overflow

Too many initializers were present for the given array. The excess initializers were ignored.

Make sure that the array elements and initializers match in size and quantity.


Compiler Warning (level 1) C4047

'identifier1' : 'operator' : different levels of indirection from 'identifier2'

Indirection refers to accessing a variable through a pointer. Just as a pointer can refer, or point, to a variable (one level of indirection), a pointer can also point to another pointer that, in turn, points to a variable (two levels of indirection). Because two pointers that have different levels of indirection possibly refer to two different things (one could be pointing to a variable, while the other could be pointing to another pointer), the compiler issues warning C4047 whenever you include such pointers in an expression.

For example, the following code generates this warning but is compiled without change:

void main() {
    char **p;// two levels of indirection
    char *q; // one level of indirection
    p = q;   // warning C4047
}


Compiler Warning (level 1) C4048

different declared array subscripts : 'identifier1' and 'identifier2'

An expression involved pointers to arrays of different size. The pointers were used without conversion.

This warning can be avoided by explicitly casting the arrays to the same or equivalent type.


Compiler Warning (level 1) C4049

compiler limit : terminating line number emission

The file contained more than 64K source lines. No line number support is available beyond this limit.


Compiler Warning (level 2) C4051

type conversion; possible loss of data

Two data items in an expression had different base types, causing the type of one item to be converted. During the conversion, a data item was truncated.

This warning can be avoided by casting the data items to the appropriate type.


Compiler Warning (level 1) C4052

function declarations different; one contains variable arguments

One declaration of the function did not contain variable arguments, but another did.

The declaration containing the variable arguments was used.


Compiler Warning (level 1) C4053

one void operand for '?:'

An expression of type void was used as an operand.

The expression was evaluated using an undefined value for the void operand.


Compiler Warning (level 1) C4054

'conversion' : from function pointer 'type1' to data pointer 'type2'

A function pointer was cast to a data pointer.

Make sure that the correct cast is being used.

This condition generates an error with the C compiler with the /Za ANSI-compatibility command-line option.


Compiler Warning (level 1) C4055

'conversion' : from data pointer 'type1' to function pointer 'type2'

A data pointer was cast to a function pointer.

Make sure that the correct cast is being used.

This condition generates an error with the C compiler with the /Za ANSI-compatibility command-line option.


Compiler Warning (level 2) C4056

overflow in floating point constant arithmetic

The compiler generated an exception while doing floating-point constant arithmetic during compilation.

For example:

double fp_val = 1.0e300 * 1.0e300;

In this example, the result of the multiplication exceeds the maximum allowable value for a double-precision data item.

Sometimes this warning occurs because of optimizations the compiler performs in calculating constant arithmetic. You can safely ignore this warning if it goes away when you turn off optimization (/Od).


Compiler Warning (level 4) C4057

'operator' : 'identifier1' indirection to slightly different base types from 'identifier2'

The pointer expressions used with the given operator had different base types.

The pointer expressions were used without conversion.

This warning can be caused by mixing signed and unsigned types, and short and long types.


Compiler Warning (level 1) C4058

unions are now aligned on alignment requirement, not size

Structures in a header file compiled with Microsoft Visual C++ may not be aligned exactly as were structures in a library compiled with Microsoft C version 6 or earlier. This can happen only if /Zp4 or greater is selected to pack structures on 4 (or more) byte boundaries.

Recompile the library with Visual C++ if the source is available. Alternatively, insert members into the structure that contains the union, placing them after the union, to make the structure the same size as it was when compiled with MS C version 6.

If you cannot recompile to meet the new alignment requirement, you can turn this warning off using #pragma warning(4058 : off).


Compiler Warning (level 1) C4059

pascal string too big, length byte is length % 256

A string followed by the pascal escape sequence (\p) can be at most 255 characters in length. The string was truncated.


Compiler Warning (level 3) C4060

switch statement contains no 'case' or 'default' labels

The following example causes this warning:

void func( int i )
{
   switch( i );   // warning
}


Compiler Warning (level 4) C4061

enumerate 'identifier' in switch of enum 'identifier' is not explicitly handled by a case label

The specified enumerate did not have an associated handler in a switch statement.

The following example causes this warning

enum E { a, b, c };
void func ( E e )
{
   switch(e)
   {
   case a:
   case b:
   default:
      break;
   }        // warning, enumerate 'c' not handled by a case label
}


Compiler Warning (level 3) C4062

enumerate 'identifier' in switch of enum 'identifier' is not handled

The specified enumerate did not have an associated handler in a switch statement, and there was no default label.

The following example causes this warning

enum E { a, b, c };
void func ( E e )
{
   switch(e)
   {
   case a:
   case b:
      break;    // no default label
   }            // warning, enumerate 'c' not handled
}


Compiler Warning (level 3) C4063

case 'identifier' is not a valid value for switch of enum 'identifier'

The specified identifier was used as a case label in a switch statement.

The following example causes this warning

enum E { a, b };
void func ( E e )
{
   switch(e)
   {
   case a:
   case b:
   case 7:      // invalid switch value
      break;    // no default label
   }
}


Compiler Warning (level 3) C4064

switch of incomplete enum 'identifier'

A switch statement specified a selector of an enumerated type that was not defined.

The following example causes this warning

enum E;
void func ( E e )
{
   switch(e)
   {
   case 7:
      break;  // warning, E not defined
   }
}


Compiler Warning (level 3) C4065

switch statement contains 'default' but no 'case' labels

The switch statement specified only a default case. It is functionally equivalent to a sequence of statements.

The following example causes this warning:

void func(int i)
{
   switch(i)
   {
   default:
      func(8);
   }                // warning detected on this line
}


Compiler Warning (level 3) C4066

characters beyond first in wide-character constant ignored

The compiler processes only the first character of a wide-character constant.


Compiler Warning (level 1) C4067

unexpected tokens following preprocessor directive - expected a newline

Extra characters followed a preprocessor directive and were ignored. This warning appears only when compiling with the /Za ANSI-compatibility option.

For example, the following code generates this warning:

#endif    NO_EXT_KEYS

If you compile with /Ze or use comment delimiters, this warning will not be generated, as in:

#endif    /* NO_EXT_KEYS */


Compiler Warning (level 1) C4068

unknown pragma

The compiler did not recognize a pragma and ignored it.

Make sure that the pragma is allowed by the type of compiler being used.


Compiler Warning (level 3) C4069

long double is the same precision as double

On some platforms, such as those based on the R4000 processor, a long double has the same precision as a double.


Compiler Warning (level 1) C4070

return of a 'void' expression

This warning is given only when Microsoft extensions are enabled (/Ze) and the C language is used.


Compiler Warning (level 2) C4071

'function' : no function prototype given

The given function was called before the compiler found the corresponding function prototype.

The function will be called using the default rules for calling a function without a prototype.


Compiler Warning (level 1) C4072

'function' : no function prototype on 'convention' function

The given function was called before the compiler found the corresponding function prototype.

The function will be called using the default rules for calling a function without a prototype.


Compiler Warning (level 3) C4073

initializers put in library initialization area

The #pragma init_seg( lib ) statement was used. The library initialization area should be used only by third-party library developers.

This warning is informational.


Compiler Warning (level 1) C4074

initializers put in compiler reserved initialization area

The #pragma init_seg( compiler ) statement was used. The compiler initialization area is reserved by Microsoft.

Code in this area may be executed before C run-time library initialization.


Compiler Warning (level 1) C4075

initializers put in unrecognized initialization area

You used an unrecognized section name with #pragma init_seg. Check the spelling.


Compiler Warning (level 1) C4076

'type' : may be used on integral types only

The signed or unsigned type modifier was used with a nonintegral type.

The given qualifier was ignored.

The following example generates this warning:

unsigned double x;


Compiler Warning (level 1) C4077

unknown check_stack option

An unknown option was given with the old form of the check_stack pragma. With the old form, the argument to the pragma must be empty, +, or -.

The current state of stack checking was left unchanged.

For example, the following generates this warning:

#pragma check_stack yes

The following code corrects this situation:

#pragma check_stack +    // Old form

or

#pragma check_stack (on) // New form


Compiler Warning (level 1) C4078

case constant 'value' too big for the type of the switch expression

A value appearing in a case statement was larger than the size of the type used in the switch expression. The compiler cast the type of the case constant to that of the switch expression.

A problem can occur when two case constants have different values before being cast but the same value afterward.


Compiler Warning (level 1) C4079

unexpected token 'token'

An unexpected separator token was found in the argument list of a pragma.

The remainder of the pragma was ignored.

The following example generates this warning:

#pragma comment( "Kilroy was here", )


Compiler Warning (level 1) C4080

expected identifier for segment name; found 'symbol'

The name of the section (segment) in #pragma alloc_text must be a string or an identifier.


Compiler Warning (level 1) C4081

expected 'token1'; found 'token2'

The compiler expected to encounter token1 (whether a comma, left or right parenthesis, string, integer) but instead found token2.

The following example generates this warning:

#pragma optimize) "l", on )


Compiler Warning (level 1) C4082

expected an identifier; found 'token'

An identifier was missing from the argument list.

The remainder of the pragma was ignored.


Compiler Warning (level 1) C4083

expected 'token'; found identifier 'identifier'

This warning is generated when the compiler is parsing a #pragma statement, and an identifier is found where it is not expected.

The following example generates this warning:

#pragma warning disable:4083   //warning
#pragma warning(disable:4083)   //correct

Check the syntax of the #pragma directives in order to fix the problem.


Compiler Warning (level 1) C4084

expected a pragma keyword; found 'token'

The token following #pragma was not recognized as a directive.

The pragma was ignored.

The following example generates this warning:

#pragma (on)


Compiler Warning (level 1) C4085

expected 'on' or 'off'

The pragma expected an on or off parameter, but the specified parameter was unrecognized or missing.

The pragma was ignored.

The following example generates this warning:

#pragma optimize( "t", maybe )


Compiler Warning (level 1) C4086

expected pragma parameter to be '1', '2', '4', '8', or '16'

The pragma expected a parameter of either 1, 2, 4, 8, or 16; but the specified parameter was not recognized or was missing.

The following example generates this warning:

#pragma pack( 3 )


Compiler Warning (level 1) C4087

'function' : declared with 'void' parameter list

The given function was declared with no formal parameters, but a call to the function specified actual parameters.

The extra parameters were passed according to the calling convention used on the function.

The following example generates this warning:

int f1( void );
f1( 10 );


Compiler Warning (level 1) C4088

'function' : pointer mismatch in actual parameter 'number', formal parameter 'number'

The actual parameter passed to the given function had a different level of indirection than the corresponding formal parameter.

The actual parameter will be passed without change. Its value will be interpreted as a pointer by the called function.


Compiler Warning (level 1) C4089

'function' : different types in actual parameter 'number', formal parameter 'number'

The actual parameter passed to the given function had a different type than the corresponding formal parameter.

The actual parameter will be passed without change. The function will cast the actual parameter to the type specified in the function definition.


Compiler Warning (level 1) C4090

'operation' : different 'modifier' qualifiers

The given operation was performed on a variable that was defined with the specified modifier. As a result, the variable could be modified without being detected by the compiler.

This warning often occurs when a pointer to an item declared as const or volatile is assigned to a pointer that was not declared as pointing to either of these type modifiers.

The expression was compiled without modification.

The following example generates this warning:

const  char *p = "abcde";
int    str( char *s );
str( p );


Compiler Warning (level 2) C4091

'extended-attribute' : ignored on left of 'type' when no variable is declared

A __declspec attribute specified in the beginning of a user-defined type declaration applies to the variable of that type. This compiler warning is generated when no variable is declared. For example:

__declspec(dllimport) class X {}; // generates C4091

// correct: the __declspec attribute applies to varX
__declspec(dllimport) class X {} varX;

The __declspec attribute placed after the class or struct keyword applies to the user defined type. For example:

class __declspec(dllimport) X {};

In this case, the __declspec attribute applies to X.


Compiler Warning (level 4) C4092

sizeof returns 'unsigned long'

The operand of the sizeof operator was very large, so the sizeof operator returned an unsigned long.

This warning occurs only under the default /Ze Microsoft extensions. Under the /Za ANSI-compatibility option, this condition truncates the result of the sizeof operator.


Compiler Warning (level 3) C4093

unescaped newline in character constant in inactive code

The constant expression of an #if, #elif, #ifdef, or #ifndef preprocessor directive evaluated to zero, making the code that follows inactive. Within that inactive code, a newline character appeared within a set of single or double quotation marks.

All text until the next double quotation mark was considered to be within a character constant.


Compiler Warning (level 2) C4094

untagged 'token' declared no symbols

The compiler detected an empty declaration using an untagged structure, union, or class.

The declaration was ignored.

The following example generates this warning:

struct  { };

This condition generates an error with the /Za ANSI-compatibility command-line option.


Compiler Warning (level 1) C4095

expected ')'; found 'token'

More than one argument was given for a pragma that can take only one argument.

The compiler assumed the expected right parenthesis and ignored the remainder of the line.

The following example generates this warning:

#pragma inline_depth( 10, 18, 67 )


Compiler Warning (level 2) C4096

'attribute1' must be used with 'attribute2'

Attribute2 requires the use of attribute1.

For example, using a variable number of arguments (...) requires that __cdecl be used. Also, __interrupt functions must be __far and __cdecl.

The compiler assumed the attribute1 attribute for the function.

Here is an example of the type of code that can cause this problem.

When compiling the project files that contain the following preprocessor directive:

#include <oledlg.h>

with the /Gr switch, the compiler generates the following warning statement:

d:\msdev4\include\oledlg.h(1689): warning C4096 ‘__cdecl’ must be used with ‘...’

The /Gr switch sets __fastcall to be the default calling convention. Because CDECL in the prototype is defined to nothing, the warning points to the location of the prototype:

int EXPORT FAR CDECL OleUIPromptUserA(int nTemplate, HWND hwndParent, ...)

The above example can be fixed by adding the following preprocessor directive to the project:

#define DOSWIN32

which defines CDECL properly.


Compiler Warning (level 3) C4097

typedef-name 'identifier1' used as synonym for class-name 'identifier2'

A typedef name which names a class is itself a class name. However, only a class declared without a tag can be named. In the following line of code the typedef name P is promoted to class name but Q is not.

typedef struct { int member; } P, Q;

Q remains a normal typedef name and a synonym for the class.

The following example causes this warning:

typedef struct _T
{
    int i;
} T;

struct U : T
{
    int j;
};               // warning

struct V : _T
{
    int j;
};               // OK


Compiler Warning (level 1) C4098

'function' : void function returning a value

A function that was declared with a return type of void contained a return statement that returned a value.

The compiler assumed the function returned a value of type int.


Compiler Warning (level 2) C4099

'identifier' : type name first seen using 'objecttype1' now seen using 'objecttype2'

The specified object was declared as either a structure or a class but was defined as a class or a structure, respectively.

The object type given in the definition was used.


Compiler Warnings C4100 Through C4192

The following topics cover compiler warnings C4100 through C4192.


Compiler Warning (level 4) C4100

'identifier' : unreferenced formal parameter

The given formal parameter was never referenced in the body of the function for which it was declared.

This warning is for informational purposes only.


Compiler Warning (level 3) C4101

'identifier' : unreferenced local variable

The given local variable was never used.

This warning is informational.


Compiler Warning (level 3) C4102

'label' : unreferenced label

The given label was defined but never referenced.

This warning is informational.


Compiler Warning (level 1) C4103

'filename' : used #pragma pack to change alignment

The given include file used the pack pragma to change the default structure alignment.

This warning is informational.


Compiler Warning (level 1) C4104

'identifier' : near data in same_seg pragma; ignored

The given near variable was specified in a same_seg pragma.

The same_seg pragma applies only to external far variables.

The identifier was ignored.


Compiler Warning (level 1) C4105

'identifier' : code modifiers only on function or pointer to function

The given identifier was declared with a code modifier that can be used only with a function or function pointer.

The code modifier was ignored.


Compiler Warning (level 1) C4106

pragma requires an integer between 1 and 127

An integer constant between 1 and 127 must be specified with the page and skip pragmas.

The compiler assumed a value of 1.

The following example generates this warning:

#pragma skip( 0 )


Compiler Warning (level 1) C4107

pragma requires an integer between 15 and 255

An integer constant between 15 and 255 must be specified with the pagesize pragma.

The compiler assumed a value of 63.

The following example generates this warning:

#pragma pagesize( 10 )


Compiler Warning (level 1) C4108

pragma requires an integer between 79 and 132

An integer constant between 79 and 132 must be specified with the linesize pragma.

The compiler assumed a value of 79.

The following example generates this warning:

#pragma linesize( 42 )


Compiler Warning (level 1) C4109

unexpected identifier 'identifier'

The pragma contained an unexpected token.

The pragma was ignored.

The following example generates this warning:

#pragma optimize( on, off )


Compiler Warning (level 1) C4110

unexpected token 'number'

The pragma contained an unexpected integer constant.

The pragma was ignored.

The following example generates this warning:

#pragma title( 1984 )


Compiler Warning (level 1) C4111

unexpected token 'string'

The pragma contained an unexpected string.

The pragma was ignored.

The following example generates this warning:

#pragma linesize( "92" )


Compiler Warning (levels 1 and 4) C4112

#line requires an integer between 1 and 32767

The #line directive specified an integer outside the permitted range.

If the given line number is less than 1, the line counter is reset to 1. If the given line number is greater than 32767, it is used as is.

This is a level 1 warning under the /Za ANSI-compatibility command-line option and a level 4 warning with the default /Ze Microsoft extensions.


Compiler Warning (level 1) C4113

'identifier1' differs in parameter lists from 'identifier2'

A function pointer was assigned to another function pointer, but the formal parameter lists of the functions do not agree.

The assignment was compiled without modification.


Compiler Warning (level 1) C4114

same type qualifier used more than once

A type qualifier (const, volatile, signed, or unsigned) was used more than once in the same type declaration or definition.

The second occurrence of the qualifier was ignored. This is a warning when Microsoft extensions are enabled (/Ze) and an error when extensions are disabled (/Za).

The following is an example of this warning:

volatile volatile int i;   // warning


Compiler Warning (levels 1 and 3) C4115

'type' : named type definition in parentheses

The given symbol was used to define a structure, union, or enumerated type inside a parenthetical expression. The scope of this definition may be unexpected.

In a C function call, the definition has global scope. In a C++ function call, the definition has the same scope as the function being called.

This warning can also be caused by declarators within parentheses (such as prototypes) that are not parenthetical expressions.

This is a level-1 warning with C++ programs or under the /Za ANSI- compatibility command-line option. It is level 3 otherwise.

The following example causes this warning:

void func(struct S *);  /* warning */

This warning can be avoided by declaring or defining the structure outside of the parentheses before the line that caused this warning, as in:

struct S;
void func(struct S *);

or:

struct S
{
   int mem;
};
void func(struct S *);


Compiler Warning (level 1) C4116

unnamed type definition in parentheses

A structure, union, or enumerated type with no name was defined in a parenthetical expression. The type definition is meaningless.

In a C function call, the definition has global scope. In a C++ function call, the definition has the same scope as the function being called.


Compiler Warning (level 1) C4117

macro name 'name' is reserved; 'command' ignored

The given command attempted to define or undefine the predefined macro name or the preprocessor operator defined.

The given command is displayed in the warning message as either #define or #undef, even if the attempt was made using command-line options.

The command was ignored.


Compiler Warning (levels 1 and 3) C4118

pragma not supported during fast compile

The pragma is not supported by the fast compiler. The pragma was ignored.

To avoid this warning when using the fast compiler, disable the pragma using #ifdef _FAST.

This is a level-1 warning, except with #pragma comment(), which causes a level-3 warning.


Compiler Warning (level 1) C4119

different bases 'base1' and 'base2' specified

The compiler cannot convert between two incompatible based pointers because they have different bases. If you want to convert based pointers, they must be based on the same thing.


Compiler Warning (level 1) C4120

based/unbased mismatch

The compiler cannot convert between the two pointers because one is a based pointer and the other is not.


Compiler Warning (level 4) C4121

'symbol' : alignment of a member was sensitive to packing

The given symbol was aligned to the current packing alignment.

The default alignment of structures can be specified with #pragma pack or the /Zp command-line option.


Compiler Warning (level 1) C4122

'function' : alloc_text applicable only to functions with C linkage

The alloc_text pragma can be applied only to functions declared with extern c. This pragma cannot be used with external C++ functions.

The alloc_text pragma was ignored.


Compiler Warning (level 1) C4124

__fastcall with stack checking is inefficient

The __fastcall keyword was used when stack checking was enabled.

The __fastcall calling convention is used for generating faster code, but stack checking causes slower code to be generated. Use the /Gs option or the check_stack pragma to turn off stack checking when using __fastcall.

This warning is informational and is issued only for the first function declared under these conditions.


Compiler Warning (level 4) C4125

decimal digit terminates octal escape sequence

An octal escape sequence in a character or string constant was terminated by a decimal digit.

The compiler evaluated the octal number without the decimal digit and assumed the decimal digit was a character.

The following example generates this warning:

char array1[] = "\\709";

If the digit 9 was intended as a character and was not a typing error, correct the example as follows:

char array[] = "\\0709";  /* String containing "89" */


Compiler Warning (level 1) C4126

'option' : unknown memory-model command-line option

The character or characters used with the /A option were not recognized as a valid memory-model specifier.

The option was ignored.


Compiler Warning (level 4) C4127

conditional expression is constant

The controlling expression of an if statement or while loop evaluated to a constant.

As a result, the code in the body of the if statement or while loop either always executes or never executes.

This warning is informational.


Compiler Warning (level 4) C4128

storage-class specifier after type

A storage-class specifier (auto, extern, register, or static) appears after a type specifier in a declaration. The compiler assumed the storage-class specifier occurred before the type specifier.

New-style code places the storage-class specifier first.


Compiler Warning (level 1) C4129

'character' : unrecognized character escape sequence

The character following a backslash (\) in a character or string constant was not recognized as a valid escape sequence.

As a result, the backslash is ignored and not printed, and the character following the backslash is printed.

To print a single backslash, specify a double backslash (\\).


Compiler Warning (level 4) C4130

'operator ' : logical operation on address of string constant

The operator was used with the address of a string literal. Unexpected code was generated.

For example, the following code generates this warning:

char *pc;
pc = "Hello";
if (pc == "Hello")
   { }

The if statement compares the value stored in the pointer pc to the address of the string "Hello", which is allocated separately each time the string occurs in the code. The if statement does not compare the string pointed to by pc with the string "Hello".

To compare strings, use the strcmp function.


Compiler Warning (level 4) C4131

'function' : uses old-style declarator

The specified function declaration is not in prototype form.

Old-style function declarations should be converted to prototype form.

An example of an old-style declaration is:

 int addrec( name, id )
 char *name;
 int id;
 { }

The new-style prototype form is:

 int addrec( char *name, int id )
 { }


Compiler Warning (level 4) C4132

'object' : const object should be initialized

The constant was not initialized.

Because the value of a symbol with the const attribute cannot be changed after its definition, it should be given an initialization value.

It will not be possible to assign a value to object.


Compiler Warning (level 3) C4133

'type' : incompatible types - from 'type1' to 'type2'

An attempt was made to subtract two pointers of different types.

This warning can be avoided by providing the appropriate type cast.


Compiler Warning (level 4) C4134

conversion between pointers to members of same class

A pointer to one member of a class was converted to a pointer to another member of the class. This is necessary because void pointers to members are not allowed.

This warning is informational.


Compiler Warning (level 3) C4135

conversion between different integral types

Information was lost between two integral types.

Tips

This warning can be avoided by providing the appropriate type cast. For example, the following code generates this warning:

void main(void)
{
   int intvar;
   long longvar;
   intvar = longvar;  // warning
// intvar = (int) longvar; // No warning for this line
}


Compiler Warning (level 3) C4136

conversion between different floating-point types

Information was lost or truncated in the conversion between two floating-point types.

For example, the following code generates this warning:

double doublevar;
float floatvar;
floatvar = doublevar;

Note that unsuffixed floating-point constants have type double, so the following code generates this warning:

floatvar = 1.0;

If the floating-point constant should be treated as type float, use the F (or f) suffix on the constant to prevent the warning:

floatvar = 1.0F;


Compiler Warning (level 1) C4137

'function' : no return value from floating-point function

The given function had no return statement.

A long double function returns its value on the floating-point stack or the emulation stack. If the function does not return a value, a run-time floating-point stack underflow error may occur.

Make sure that all floating-point functions return a floating-point value.


Compiler Warning (level 1) C4138

'*/' found outside of comment

The compiler found a closing comment delimiter (*/) without a preceding opening delimiter. The compiler assumed a space between the asterisk (*) and the forward slash (/).

The following example generates this warning:

int */*comment*/ptr;

In this example, the first comment delimiter is ambiguous.

Usually, the cause of this warning is an attempt to nest comments.

To comment out sections of code that may contain comments, enclose the code in an #if/#endif block and set the controlling expression to zero, as in:

#if 0
int my_variable;   /* Declaration currently not needed */
#endif


Compiler Warning (level 1) C4139

'hexnumber' : hex escape sequence is out of range

A hexadecimal escape sequence appearing in a character or string constant was too large to be converted to a character.

If the hexadecimal escape sequence is in a string constant, the compiler casts the low byte of the hexadecimal number to a char. If in a char constant, the compiler made the cast and then sign extended the result. If in a char constant and the program was compiled with the /J command-line option, the compiler cast the value to an unsigned char.

Note that the following code generates this warning:

printf("\x7Bell\n");

The compiler reads the characters "7Be" as a legal hexadecimal number, but it is too large to fit in a character. To correct this example, use three hexadecimal digits:

printf("\007Bell\n");


Compiler Warning (level 1) C4141

'modifier' : used more than once

The specified modifier was repeated in statement.

The following example causes this warning:

inline inline void func ();   // warning


Compiler Warning (level 1) C4142

benign redefinition of type

A type was redefined, but the redefinition had no effect on the code generated.

This warning commonly occurs in these cases:

  • The return type of a member function of a derived class differed from the return type of the corresponding overridden member function.

  • A type defined with the typedef command is redefined using different syntax. For example, the following code causes this warning when generating 16-bit code:
      typedef   unsigned int WORD;
  typedef   unsigned short WORD;

This warning is informational.


Compiler Warning (level 1) C4143

pragma 'same_seg' not supported; use __based allocation

The #pragma same_seg is no longer supported. Use the __based keyword instead.


Compiler Warning (level 1) C4144

'expression' : relational expression as switch expression

The given relational expression was used as the control expression of a switch statement. The associated case statements will be offered Boolean values.

This warning is informational.


Compiler Warning (level 1) C4145

'expression1' : relational expression as switch expression; possible confusion with 'expression2'

The given relational expression expression1 was used as the control expression of a switch statement. The associated case statements will be offered Boolean values.

The given expression expression2 is a suggested case expression.

This warning is informational.


Compiler Warning (level 3) C4146

unary minus operator applied to unsigned type, result still unsigned

The variable should be cast to a signed type if it must contain a signed value. Its type is still unsigned.

The following example causes this warning:

void func()
{
   unsigned int ui;
   -ui;              // warning
}


Compiler Warning (level 2) C4150

deletion of pointer to incomplete type 'type'; no destructor called

The delete operator was called to delete the given type, which was declared but not defined. The compiler was unable to find any destructors for the given type.

Make sure that the class, structure, or union is defined before using the delete operator.

The following example generates this warning:

class  IncClass;
void   NoDestruct( IncClass* pIncClass )
  {   delete pIncClass;   }


Compiler Warning (level 4) C4152

non standard extension, function/data ptr conversion in expression

A pointer to a function was converted to a pointer to data, or visa versa.

This conversion is allowed when the Microsoft extensions (/Ze) are enabled. However, ANSI C does not allow this conversion.


Compiler Warning (level 1) C4153

function/data pointer conversion in expression

A pointer to a function was converted to a pointer to data, or vice versa.

This conversion is not legal in ANSI C.

This conversion is allowed when the Microsoft extensions (/Ze) are enabled, and causes a level-4 warning.


Compiler Warning (level 1) C4154

deletion of an array expression; conversion to pointer supplied

Use of delete on an array is undefined.

The array was converted to a pointer. For example, if your array was:

char A[]

it would be converted to:

char A*

The following example causes this warning:

void func()
{
   int array[ 10 ];
   delete array;       // warning
}


Compiler Warning (level 1) C4155

deletion of an array expression without using the array form of 'delete'

Deletion of an array by the non-array form of delete is undefined.

This warning is generated only when the /Za ANSI-compatibility switch is enabled.

The following example causes this warning:

T (*array)[ 10 ] = new T[ 5 ][ 10 ];
delete array;                         // warning


Compiler Warning (level 2) C4156

deletion of an array expression without using the array form of 'delete'; array form substituted

Deletion of an array by the non-array form of delete is undefined. The compiler used translated the expression to use the array form of 'delete'.

This warning is generated only when the Microsoft extensions (/Ze) are enabled.

T (*array)[ 10 ] = new T[ 5 ][ 10 ];
delete array;     // warning, changed by compiler to "delete [] array;"


Compiler Warning (level 1) C4157

pragma was ignored by C compiler

The init_seg() pragma is used by the C++ compiler only.


Compiler Warning (level 1) C4158

assuming #pragma pointers_to_members(full_generality, inheritance)

A #pragma pointers_to_members(single|multiple|virtual) was issued without an accompanying #pragma pointers_to_members(full_generality).


Compiler Warning (level 3) C4159

#pragma pack(pop,...) : has popped previously pushed identifier 'identifier'

Your source code contains a #pragma pack(pop), which does not specify an identifier, following a #pragma pack(push, id). The identifier id was popped; subsequent uses of id may cause unexpected behavior.

To avoid this warning, explicitly identify id with the pop, as in #pragma pack(pop, id).


Compiler Warning (level 3) C4160

#pragma pack(pop,...) : did not find previously pushed identifier 'identifier'

A statement in your source code tried to pop an identifier which had not been pushed. This problem could be caused by a push or a pop that incorrectly specifies an identifier.

To fix this ensure that all pops specify identifiers that have indeed previously been pushed.


Compiler Warning (level 3) C4161

#pragma pack(pop...) : more pops than pushes

Because your source code contains one more pop than there are pushes the #pragma pack stack may not behave as you would expect.

To fix this, ensure that your code includes the same number of pops as pushes.


Compiler Warning (level 1) C4162

'identifier' : no function with C linkage found

The specified function with C linkage was declared but could not be found.


Compiler Warning (level 1) C4163

'identifier' : not available as an intrinsic function

The specified function cannot be used as an intrinsic function.


Compiler Warning (level 1) C4164

'identifier' : intrinsic function not declared

The specified intrinsic function was not declared.


Compiler Warning (level 1) C4165

convention function cannot take a variable number of arguments

A function with the specified calling convention cannot be used with a variable number of arguments.


Compiler Warning (level 1) C4166

illegal calling convention for constructor/destructor

Constructors and destructors cannot have calling conventions other than the default for the platform (except when you explicitly specify __stdcall).


Compiler Warning (level 1) C4167

function : only available as an intrinsic function

The specified function can only used in its intrinsic form. The directive to create a function call was ignored.

Your code used #pragma function to attempt to force the compiler to use the conventional function form of the specified function. However, the specified function is available only as an intrinsic.

Using #pragma function will not affect the specified function. You can avoid this warning by removing the #pragma function statement.

The following example causes this warning:

#include <malloc.h>
#pragma function(_alloca )   // warning: _alloca() is intrinsic only
void main(){}


Compiler Warning (level 1) C4168

compiler limit : out of debugger types, delete program database 'database' and rebuild

The specified program database file must be rebuilt to accommodate all types in the program being compiled.


Compiler Warning (level 1) C4170

unexpected end of file found

The file ended with a line-continuation character. The following example causes this warning:

#define BOTTESINI    \
if (1) {             \
}                    \


Compiler Warning (level 1) C4171

'identifier' : modifier functions require prototypes

A function with the __pascal or __fastcall calling convention was not prototyped or had an old-style prototype.

The following example shows old and new style function prototypes:

void __fastcall func1 ( i, j );      // old-style
void __fastcall func2 ( int i, int ) // new style


Compiler Warning (level 1) C4172

returning address of local variable or temporary

A function returned the address of a local variable or a temporary. Local variables and temporaries are destroyed when a function returns; consequently the address returned will almost certainly be invalid.

When returning the address of a variable, you should return the address of a global variable or a dynamically allocated variable, which will continue to exist after the function ends.


Compiler Warning (level 1) C4173

enabling the option option will hinder the performance of incremental compilation

This warning is not used.


Compiler Warning (level 1) C4174

'name' : not available as a #pragma component

The component pragma was specified incorrectly.

The following example shows an incorrect and a correct way to use the component pragma:

#pragma component(info)  // warning; unknown
#pragma component(browser, off)  // turn off browse info


Compiler Warning (level 1) C4175

#pragma component(browser, on) : browser info must initially be specified on the command line

The component pragma is useful only if you’ve specified that browse information be generated during compilation. From the Build menu, choose Settings; then select the C/C++ tab of the Project Settings dialog box and select the Generate Browse Info check box. If you’re compiling from the command line, specify the /FR option.


Compiler Warning (level 1) C4176

'subcomponent' : unknown subcomponent for #pragma component browser

The component pragma was specified incorrectly.

If you wish to exclude references to a particular name, you must specify the references option before the name. The following example shows the incorrect and correct ways to exclude references to NULL:

#pragma component(browser, off, i)  // warning
#pragma component(browser, off, references, i) // ok


Compiler Warning (level 1) C4177

pragma 'identifier' should be at global scope

The specified pragma should not be placed within a function.


Compiler Warning (level 1) C4178

case constant 'constant' too big for the type of the switch expression

The specified constant in a switch expression was too large to fit in the type to which it was assigned. The following example causes this warning:

void main()
{
    int i;  // maximum size of unsigned long int is 4294967295
    switch( i )
    {
        case 4294967295:   // OK
            break;
        case 4294967296:   // warning
            break;
    }
 }


Compiler Warning (level 1) C4179

'//*' : parsed as '/' and '/*': confusion with standard '//' comments

The compiler found incorrect comment delimiters. Use // or /*.


Compiler Warning (level 1) C4180

qualifier applied to function type has no meaning

This warning is generated when a qualifier (such as const) is applied to a function type defined by typedef. For example:

typedef int *FuncType(void);

//the const qualifier cannot be applied to the
//function type FuncType, generates warning:
const FuncType f;


Compiler Warning (level 1) C4181

qualifier applied to reference type ignored

This warning is generated when a qualifier (such as const) is applied to a reference type defined by typedef. For example:

typedef int &RefInt;
int I;
const RefInt cri=i; //generates warning C4181


Compiler Warning (level 1) C4183

'identifier' : member function definition looks like a ctor, but name does not match enclosing class

The inline definition of a member function in a class or a structure looks like a constructor, but the name of the member function is not the same as the class or structure name enclosing it. This member function is assumed to have a default return type of int. For example:

class MyClass1;
class MyClass2 {
   MyClass1() {...};
}

The member function X() is treated as int X().

Make sure the constructor of this class is not misspelled. Misspelled constructors can lead to run time errors that are hard to isolate. If this member function is not intended to be a constructor, you can avoid this warning by explicitly specifying the return type of the member function.


Compiler Warning (level 1) C4185

ignoring unknown #import attribute 'attribute'

The attribute is not a valid attribute of #import. It is ignored. For example:

#import "olepro32.dll" no_such_attribute

The attribute no_such_attribute does not belong to #import.


Compiler Warning (level 1) C4186

#import attribute 'attribute' requires count arguments; ignored

The number of arguments supplied to an #import attribute is incorrect. For example:

#import "olepro32.dll" no_namespace("abc") rename("a","b","c")

The no_namespace attribute does not take any argument, one is supplied. The rename attribute takes only two arguments, three are supplied.


Compiler Warning (level 1) C4187

#import attributes 'attribute1' and 'attribute2' are incompatible; both ignored

Both no_implementation and implementation_only attributes are specified in the #import statement. Since the two attributes are incompatible, they are ignored.


Compiler Warning (level 4) C4189

'identifier' : local variable is initialized but not referenced"

A variable was declared and initialized but never used.


Compiler Warning (level 1) C4190

'identifier1' has C-linkage specified, but returns UDT 'identifier2' which is incompatible with C

A class, structure, or union was specified as the return type for a function or pointer to function, and the linkage was specified as extern "C". This is not illegal, but you must ensure that all calls made to this function occur from C++, and that the definition of the function is also in C++.

The following example causes this warning:

struct X
{
   int i;
   X ();
   virtual ~X ();
};

extern "C" X func ();   // warning


Compiler Warning (level 3) C4191

'operator/operation' : unsafe conversion from 'type of expression' to 'type required'

Calling this function through the result pointer may cause your program to crash.

This warning is disabled by default and level 3 if enabled. See #pragma warning for information on how to disable or enable warnings.


Compiler Warning (level 3) C4192

automatically excluding 'name' while importing type library 'library'

While doing a #import of library, an item, name, was encountered that is also defined in the Win32 system headers. Due to limitations of type libraries, names such as IUnknown or GUID will often be defined in a type library, duplicating the definition from the system headers. #import will detect these items and refuse to incorporate them in the .TLH and .TLI header files.

#import attributes no_auto_exclude and include(...) can be used to override this behavior.


Compiler Warnings C4200 Through C4554

The following topics cover compiler warnings C4200 through C4554.


Compiler Warning (levels 2 and 4) C4200

nonstandard extension used : zero-sized array in struct/union

A structure or union contained an array with zero size.

This is a level-4 warning when Microsoft extensions are enabled (/Ze) and a level-2 warning when Microsoft extensions are disabled (/Za).

The following is an example of this error:

struct S { int a[0]; };  // warning


Compiler Warning (level 4) C4201

nonstandard extension used : nameless struct/union

Microsoft C/C++ allows structure declarations to be specified without a declarator when they are members of another structure or union.

The following is an example of this error:

struct S
{
   float y;
   struct
   {
      int a, b, c;  // warning
   };
} *p_s;

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4202

nonstandard extension used : '...': prototype parameter in name list illegal

The function definition contains variable arguments, but used old-style function definition format.

The following is an example of this error:

void func( a, b, ...)
int   a, b;  // warning
{}

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4203

nonstandard extension used : union with static member variable

Microsoft C++ allows C++ programs to contain static member variables in a union. This condition will not generate a warning in C programs.

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4204

nonstandard extension used : non-constant aggregate initializer

Microsoft C++ allows you to initialize aggregate types (arrays, structures, unions, and classes) with values that are not constants.

The following is an example of this error:

int func1();
struct S1{ int i; };
S1 struct1 = { func1() };  // warning

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4205

nonstandard extension used : static function declaration in function scope

Microsoft C/C++ allows static functions to be declared inside another function. The function is given global scope.

The following is an example of this error:

void func1()
{
   static int func2();  // warning
};

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4206

nonstandard extension used : translation unit is empty

The file was empty after preprocessing.

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4207

nonstandard extension used : extended initializer form

Microsoft C/C++ allows you to initialize an unsized array of char using a string within braces.

The following is an example of this error:

char c[] = { 'a', 'b', "cdefg" };

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4208

nonstandard extension used : delete [exp] - exp evaluated but ignored

Microsoft C++ allows you to give a value within brackets when deleting an array with the delete operator. The value in brackets is ignored.

delete [18] MyArray;  // warning
delete [] MyArray;    // OK

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4209

nonstandard extension used : benign typedef redefinition

A type was redefined to be the same type as in the first definition.

The following is an example of this error:

typedef long lPulseWidth;
typedef long lPulseWidth;  // warning

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4210

nonstandard extension used : function given file scope

Under the default /Ze command-line option, Microsoft C/C++ gives function declarations file scope.

void func1()
{
    extern int func2( double );
}

void main( void )
{
    func2( 4 );    //  /Ze passes 4 as type double
}                  //  /Za passes 4 as type int

This extension can prevent your code from being portable to other compilers.


Compiler Warning (level 4) C4211

nonstandard extension used : redefined extern to static

Microsoft C/C++ allows redefinition of an extern identifier as static.

The following is an example of this error:

extern int i;
static int i;  // warning

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4212

nonstandard extension used : function declaration used ellipsis

The function prototype had variable arguments, but the function definition did not.

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4213

nonstandard extension used : cast on l-value

Microsoft C/C++ allows casts to be used on the left side of an assignment statement.

The following is an example of this error:

void *a;
void f()
{
   int   i[3];
   a = &i;
   *(( int * )a )++ = 3;  // warning
}

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4214

nonstandard extension used : bit field types other than int

Microsoft C/C++ allows bitfield structure members to be of any integral type.

The following is an example of this error:

struct bitfields
{
   unsigned short j:4;  // warning
};

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4215

nonstandard extension used : long float

Microsoft C/C++ treats long float as double. Use double to maintain compatibility.

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4216

nonstandard extension used : float long

Microsoft C/C++ treats float long as double. Use double to maintain compatibility.

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4217

nonstandard extension used : function declaration from a previous block

If a function is not visible in the current scope, Microsoft C/C++ finds function declarations that would not otherwise be available.

The following example causes this warning:

void func1()
{
   void func2();
}
void func3()
{
   func2();   // warning
}

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4218

nonstandard extension used : must specify at least a storage class or a type

Microsoft C/C++ allows you to declare a variable without specifying a type or storage class. The default type is int.

The following example causes this warning:

i;  // warning

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 1) C4219

nonstandard extension used : trailing ',' used for variable argument list

A variable argument list ended with a comma but no ellipsis.

The following example causes this warning:

int func1( int first, );       // warning
int func2( int first, ... );   // OK


Compiler Warning (level 4) C4220

varargs matches remaining parameters

There was an attempt to compare pointers to functions that had similar parameters, but with one having variable arguments.

The following example causes this warning:

int ( *pFunc1) ( int a, ... );
int ( *pFunc2) ( int a, int b);
if ( pFunc1 != pFunc2 ) {};  // warning

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4221

nonstandard extension used : 'identifier' : cannot be initialized using address of automatic variable

Microsoft C/C++ allows you to initialize an aggregate type (array, struct, or union) with the address of a local (automatic) variable.

The following example causes this warning:

struct S
{
   int *i;
};
void func()
{
   int j;
   struct S s1 = { &j };  // warning
}

This extension can prevent your code from being portable to other compilers and will generate an error under the /Za command-line option.


Compiler Warning (level 4) C4222

nonstandard extension used : 'identifier' : 'static' should not be used on member functions defined at file scope

A static member function was defined at file scope. Static member functions should be declared with external linkage.

This is a warning when Microsoft extensions are used (/Ze) and is an error when Microsoft extensions are disabled (/Za).

The following is an example of this error:

class C
{
   static void func();
};

static void C::func(){};    // warning


Compiler Warning (levels 1 and 4) C4223

nonstandard extension used : non-lvalue array converted to pointer

Standard C does not permit a non-lvalue array to be converted to a pointer; Microsoft C/C++, however, permits conversion. This warning simply points out a portion of code that is non-portable.


Compiler Warning (level 1) C4224

nonstandard extension used : formal parameter 'identifier' was previously defined as a type

The specified identifier was previously used as a typedef. This causes a warning when the ANSI compatibility (/Za) option has been selected.

The following example causes this warning:

typedef int I;
void func ( int I );  // warning


Compiler Warning (level 1) C4226

nonstandard extension used : 'keyword' is an obsolete keyword

The specified keyword is not used in this version of C++.

This error can occur when using the __export keyword.

Tips

The __export keyword is obsolete in 32-bit versions of Windows. The equivalent functionality can be achieved by using the keyword __declspec with the dllexport attribute. See __declspec in the Language Quick Reference for more information.


Compiler Warning (level 1) C4227

anachronism used : qualifiers on reference are ignored

Here anachronism means an outdated usage. You should avoid using qualifiers like const or volatile with C++ references as this example shows:

int j = 0;
int &const i = j; /* warning C4227 */


Compiler Warning (level 1) C4228

nonstandard extension used : qualifiers after comma in declarator list are ignored

You should not use qualifiers like const or volatile after the comma when delcaring variables. The following example shows the error:

int j, const i = 0;  /* warning C4228 */

To fix the problem, rewrite the example as:

int j;
int const i = 0;


Compiler Warning (level 1) C4229

anachronism used : modifiers on data are ignored

An anachronism is an outdated usage. Here it refers to using a Microsoft modifier such as __cdecl on a data declaration. In this example, __cdecl is ignored:

int __cdecl counter;


Compiler Warning (level 1) C4230

anachronism used : modifiers/qualifiers interspersed, qualifier ignored

An anachronism is an outdated usage. Here it refers to using a qualifier before a Microsoft modifier such as __cdecl. In this example, const is ignored:

int __cdecl const function1();


Compiler Warning (level 3) C4231

nonstandard extension used : 'identifier' before template explicit instantiation

When Microsoft extensions are enabled (/Ze), an extern template can be instantiated, generating this warning. Otherwise, this will cause an error.

The following example causes this warning:

template<class T, int i> class MyStack {};
extern template MyStack< int, 4>;


Compiler Warning (level 4) C4232

nonstandard extension used : 'identifier' : address of dllimport 'dllimport' is not static, identity not guaranteed

A nonstatic value was given as the address of a function declared with the dllimport modifier. This results in a warning if the Microsoft extensions (/Ze) are enabled, and an error if they are not.


Compiler Warning (level 4) C4233

nonstandard extension used : 'keyword' keyword only supported in C++, not C

The compiler compiled your source code as C rather than C++, and you used a keyword that is only valid in C++. The compiler will compile your source file as C if the extension of the source file is .c or you use the /Tc command-line option (see /Tc, /Tp).


Compiler Warning (level 4) C4234

nonstandard extension used: 'keyword' keyword reserved for future use

You used a keyword that is not yet implemented in the compiler.


Compiler Warning (level 4) C4235

nonstandard extension used : 'keyword' keyword not supported in this product

You used a keyword that the compiler does not support.


Compiler Warning (level 4) C4236

nonstandard extension used : 'keyword' is an obsolete keyword, see documentation for __declspec(dllexport)

You used the _export keyword, which is now obsolete. Use __declspec(dllexport) instead.


Compiler Warning (level 4) C4238

nonstandard extension used : class rvalue used as lvalue

This error occurs when you are using Microsoft language extensions (/Ze) and use a class type as is an rvalue in a context that implicitly or explicitly takes its address. For example:

struct C
{
C();
};
C * pC = &C();   // yields C4238

This usage is not permitted by the C++ Working Paper, and in some cases (such as the example above) can be quite dangerous. This usage is being permitted under /Ze for compatibility with previous versions of the compiler, which did not flag this error. This usage is not permitted under /Za.


Compiler Warning (level 4) C4239

nonstandard extension used : 'token' : conversion from 'type' to 'type'

This type conversion is not allowed by the C++ draft standard, but it is permitted here as an extension. This warning is always followed by at least one line of explanation describing the language rule being violated.

For example:

struct C { C(); };
void func(void)
{
//Yields: warning C4239: nonstandard extension used :
//'initializing' : conversion from 'struct C' to
//'struct C&'
//A reference that is not to 'const' cannot be bound
//to a non-lvalue
   C & rC = C();
}


Compiler Warning (level 3) C4240

nonstandard extension used : access to 'classname' now defined to be 'access specifier', previously it was defined to be 'access specifier'

The proposed C++ standard does not allow the access to a nested class to be changed; the Visual C++ compiler does allow this but also generates this warning.

The following is a code sample that generates this error:

class X {
private:
   class N;
public:
   class N {
   };
};


Compiler Warning (level 3) C4241

'member' : member access is restricted

There was an attempt to access a private or protected member function or data.

If the program needs to access this member, change the object access level or make the member a friend of the function that needs to be accessed.


Compiler Warning (level 1) C4243

'conversion type' conversion exists from 'type1' to 'type2', but is inaccessible

A pointer to a derived class was converted to a pointer to a base class, but the derived class inherited the base class with private or protected access.

The following is an example of this warning:

class B {};
class D : private B {};

D d;
B *q = (B*)&d;;      // warning


Compiler Warning (levels 3 and 4) C4244

'conversion' conversion from 'type1' to 'type2', possible loss of data

An integral type was converted to a smaller integral type. This is a level-4 warning if type2 is int and the size of type1 is smaller than int. Otherwise it is a level-3 warning.

The conversion may have a problem due to implicit integral conversions. For example:

short a, b, c;
a = b + c;    // warning


Compiler Warning (level 4) C4245

'conversion' : conversion from 'type1' to 'type2', signed/unsigned mismatch

You attempted to convert a signed const that has a negative value to an unsigned.

The following code shows this warning:

const int i = -1;
unsigned int j = i; // warning C4245

const int k = 1;
unsigned int l = k; // okay

int m = -1;
unsigned int n = m; // okay


Compiler Warning (level 3) C4247

'member' not accessible because 'class1' uses 'access' to inherit from 'class2'

There was an attempt to access a member of a class that was inherited from another class with the private or protected attribute.

This is a warning instead of an error, because the access violation occurred due to a type cast.


Compiler Warning (level 3) C4248

'class1' : cannot access 'access' 'member' declared in class 'class2'

The given member cannot be accessed from this class because it did not have access rights. The member was not accessed.

This warning can be avoided by giving class1 access to members of class2 by changing the class access specifier or using the friend specifier.


Compiler Warning (level 3) C4249

'class1' : no path to 'access' 'member' declared in virtual base 'class2'

The given member of the virtual base class cannot be accessed from the derived class because it did not have access rights. The member was not accessed.

This warning can be avoided by giving class1 access to members of class2 by changing the class access specifier or using the friend specifier.


Compiler Warning (level 2) C4250

'class1' : inherits 'class2::member' via dominance

There were two or more members with the same name. The one in class2 was inherited since it was a base class for the other classes that contained this member.

This warning is for informational purposes only.


Compiler Warning (level 1) C4251

'identifier' : class 'type' needs to have dll-interface to be used by clients of class 'type2'

The specified base class was not declared with the __declspec(dllexport) keyword.

A base class or structure must be declared with the __declspec(dllexport) keyword if a function in a derived class is to be exported.


Compiler Warning (level 1) C4253

'identifier' : forming a pointer-to-member requires explicit use of the address-of operator ('&') and a qualified name

A pointer to a non-static member function of a class or structure requires the form of an & followed by the qualified identifier not enclosed in parentheses.


Compiler Warning (level 1) C4259

'identifier' : pure virtual function was not defined

This warning follows compiler error C2259. It is generated once for each undefined abstract function defined in the class specified in the C2259 error message.


Compiler Warning (level 1) C4261

no override, 'class1::func1' has 'model' calling convention whereas 'class2::func2' has 'model' calling convention

The specified functions had different calling conventions.

The Microsoft calling convention specifiers are used for disambiguation between overloaded functions.

The virtual mechanism will not be invoked for functions with differing calling conventions.

The following example causes this warning:

struct X
{
   virtual void __near func();
};
struct Y : X
{
   void __far func();  // warning
};


Compiler Warning (level 4) C4268

'identifier' : 'const' static/global data initialized with compiler generated default constructor fills the object with zeros

A const global or static instance of a non-trivial class is initialized with a compiler-generated default constructor. For example:

class X {
public:
   int m_data;
};

const X x1;   // Generates warning C4268

As this instance of the class is const, the value of m_data can never be changed.


Compiler Warning (level 1) C4269

'identifier' : 'const' automatic data initialized with compiler generated default constructor produces unreliable results

A const automatic instance of a non-trivial class is initialized with a compiler generated default constructor. For example:

class X {
public:
   int m_data;
};

void g() {
   const X x1;   //Generates the warning
};

Since this instance of the class is generated on the stack, the initial value of m_data can be anything. Also, since it is a const instance, the value of m_data can never be changed.


Compiler Warning (level 1) C4270

nonstandard extension used: 'initializing': a non-const 'type1' must be initialized with an l-value, not a function returning 'type2'

A nonconst reference must be initialized with an l-value, which makes the reference a name for that l-value. A function call is only an l-value if the return type of the function is a reference. A Microsoft extension to the C++ language allows any function call to be treated as an l-value for the purpose of initializing references. If Microsoft extensions are disabled (/Za), then this an error.

This warning can be avoided by ensuring the reference is a const reference. However, if the reference is const and the function return type is not compatible with the type of the reference, the compiler will silently generate and initialize a temporary. Although this is not incorrect, it is inefficient and probably undesirable.

The following example causes this warning:

struct X
{
   X(int);
   X(X&);
};
X f(X);
X b = f(X(2));   // warning

If you do not have access to source code to fix this problem you can disable this warning using the following pragma:

#pragma warning(disable:4270)


Compiler Warning (level 1) C4271

'identifier' : 'naked' functions cannot be 'inline'; inline expansion not performed

The specified function was declared with both the naked and inline attributes.

The following example causes this warning.

inline __declspec( naked )  int func() {}   // warning


Compiler Warning (level 1) C4273

'identifier' : inconsistent DLL linkage. dllexport assumed

The specified member function was declared in a class with dllexport linkage, and then was imported. This warning can also be caused by declaring a member function in a class with dllimport linkage as neither imported nor static nor inline.

The function was compiled as dllexport.


Compiler Warning (level 2) C4275

non – DLL-interface classkey 'identifier' used as base for DLL-interface classkey 'identifier'

An exported class was derived from a class that was not exported.


Compiler Warning (level 1) C4276

'fucntion' : no prototype provided; assumed no parameters

When taking the address of a function with the __stdcall calling convention, you need to give a prototype so the compiler can create the function’s decorated name. Since function had no prototype, the compiler is assuming it has no parameters when creating the decorated name.


Compiler Warning (level 3) C4280

'operator –>' was self recursive through type 'type'

Your code contains an incorrect use of operator–>. Check your code to make sure operator–> does not call itself.

The following code shows the problem:

struct A {
   int z;
   A& operator ->();
};

void f(A y) {
   int i = y->z; // warning C4280
}


Compiler Warning (level 3) C4281

'operator –>' recursion occurred through type 'type'

Your code contains an incorrect use of operator–>. Check your code to make sure operator–> does not call itself.

The following code shows the problem:

struct A;
struct B;
struct C;

struct A {
   int z;
   B& operator->();
};

struct B {
   C& operator->();
};

struct C {
   A& operator->();
};

void f(A p) {
   int i = p->z; // warning C4281
}


Compiler Warning (level 3) C4282

then through type 'type'

This warning shows that operator–> called itself through type type. It is a continuation of warning C4281.


Compiler Warning (level 3) C4283

and through type 'type'

This warning shows that operator–> called itself through type type. It is a continuation of warning C4281.


Compiler Warning (level 2) C4284

return type for 'identifier::operator –>' is not a UDT or reference to a UDT. Will produce errors if applied using infix notation

The operator–>( ) function must return either a pointer to a class or an object of or a reference to a class for which operator–>( ) is defined.

The following example causes this warning:

class C
{
public:
    int operator->();  // warning
};

It is meaningless to apply the member access operator to fundamental data types that have no member acess. This warning message will appear when this happens.


Compiler Warning (level 2) C4285

return type for 'identifier::operator –>' is recursive if applied using infix notation

The specified operator–>() function cannot return the same type, or a reference to the same type, for which it is defined.

The following example causes this warning:

class C
{
public:
    C operator->();   // warning
    C& operator->();  // warning
};


Compiler Warning (level 1) C4286

'type1' : is caught by base class ('type2') on line number

The specified exception type is handled by a previous handler. The type for the second catch is derived from the type of the first. Exceptions for a base class will catch exceptions for a derived class.

The following is an example of this warning:

#include <eh.h>
class C {};
class D : public  C {};
void main()
{
    try
    {
        throw "ooops!";
    }
    catch( C ) {}
    catch( D ) {}  // warning, D is derived from C
}


Compiler Warning (level 3) C4290

C++ Exception Specification ignored

A function was declared using exception specification.

At this time the implementation details of exception specification have not been standardized, and are accepted but not implemented in Microsoft Visual C++.

Code compiled with ignored exception specifications may need to be recompiled and linked to be reused in future versions supporting exception specifications.

You can avoid this warning by using the warning pragma:

#pragma warning( disable : 4290 )


Compiler Warning (level 1) C4291

'declaration' : no matching operator delete found; memory will not be freed if initialization throws an exception

A placement new is used for which there is no placement delete.

You could reproduce this error by defining the following class in a global namespace:

typedef unsigned int size_t;

class MemBuffer_t {
public:
   void *Alloc(size_t);
};

MemBuffer_t memBuffer;

void *operator new(size_t size, MemBuffer_t &rBuffer)
{
   return rBuffer.Alloc(size);
}

class X {
public:
   X(int);
};

void f()
{
   X *pX = new (memBuffer) X(10);
}

This warning will only occur if the user compiles the code with /GX, exception handling enabled.

The fix for the warning is to declare and/or define the following operator delete after you define your operator new:

void operator delete(void *pMem, MemBuffer_t &rBuffer);


Compiler Warning (level 3) C4292

'name' : 'name' is ambiguous or inaccessible; memory will not be freed if initialization throws an exception

Because an exception could happen while creating an instance of an object, the object’s destructor must be accessible and unambiguous. If it is not, the object will not be deleted correctly. You can avoid this problem by changing the access of the object’s delete operator or compiling without exception handling (/GX–).

The following example shows an inaccessible destructor:

// compiled with (/GX)
class B {
public:
    void *operator new(unsigned int);
};

class D : public B {
protected:
    void operator delete(void *);
};

class E : public D {
public:
    E();
    ~E();
};

void f()
{
    E *pE = new E; // warning C4292, delete is inaccessible (protected)
}


Compiler Warning (level 3) C4293

new in default argument will not free memory if initialization throws an exception

Because an exception could happen while creating an instance of an object, the object’s destructor must be accessible and unambiguous. If it is not, the object will not be deleted correctly. You can avoid this problem by changing the access of the object’s delete operator or compiling without exception handling (/GX–).

The following example shows an inaccessible destructor:

// compiled with (/GX)
class B {
public:
    void *operator new(unsigned int);
};

class D : public B {
protected:
    void operator delete(void *);
};

class E : public D {
public:
    E();
    ~E();
};

class X {
public:
    X(class E);
};

void f()
{
    X x(E *e = new E); // warning C4293, delete not accessible (protected)
}


Compiler Warning (level 1) C4300

conversion of pointer to non-integral type

A pointer was cast to a nonintegral type (such as float).

The cast pointer address may no longer be valid.

This warning is generated by the following example:

   int     i = 24;
   printf( "Address: %f\\n", ( float ) &i );


Compiler Warning (level 3) C4304

'identifier' : simple type cast conversion of no expression

An empty expression was cast to the specified type.

The following example causes this warning:

void func()
{
   int ();   // warning
}


Compiler Warning (level 1) C4305

'identifier' : truncation from 'type1' to 'type2'

The specified identifier type was converted to a smaller type. Information was lost in the casting.


Compiler Warning (level 3) C4306

'identifier' : conversion from 'type1' to 'type2' of greater size

The specified identifier type was cast to a larger pointer. The unfilled high bits of the new type will be zero-filled.

This warning may indicate an unwanted conversion. The resulting pointer may not be valid.


Compiler Warning (level 2) C4307

'operator' : integral constant overflow

An expression using the specified operator resulted in an integral constant that overflowed the space allocated for it, so it may be necessary to use a larger type to hold the constant. For instance, a signed int holds a smaller value than an unsigned int because the signed int uses one of its bits to represent the sign. If an arithmetic operation overflows the signed int, but can be expressed with an unsigned int, you will get this message.

The following example causes this warning:

int i = 2000000000 + 2000000000;            // warning
int j = (unsigned)2000000000 + 2000000000;  // OK


Compiler Warning (level 2) C4308

negative integral constant converted to unsigned type

An expression required that a negative integral constant be converted to an unsigned type.

The result of the expression is probably meaningless.

The following example causes this warning:

unsigned int i = 20000 + (-5);   // warning


Compiler Warning (level 2) C4309

'conversion' : truncation of constant value

The specified type conversion operation caused a constant to exceeded the space allocated for it.

It may be necessary to use a larger type to contain the constant.

The following example causes this warning:

char c = 128;                  // warning
char x = (char) 128;           // warning


Compiler Warning (level 3) C4310

cast truncates constant value

A constant value was cast to a smaller type; some information was lost.


Compiler Warning (level 1) C4340

'identifier' : value wrapped from positive to negative value

The specified enum value was greater than the largest enum positive value and so was wrapped around. After wrapping, the value was negative.


Compiler Warning (level 3) C4341

'identifier' : signed value is out of range for enum constant

A given enumerated constant exceeded the limit for an int. The value of the illegal constant is undefined.

Make sure that the given constants resolve to integers between – 32,768 and +32,767 (signed) or 0 and +65,535 (unsigned).

The following example generates this warning:

enum ELEMENTS
{
   Hydrogen = 1,
   Helium,
   Lithium,
   Beryllium,
   Impossibillium = 500000
} ;


Compiler Warning (level 1) C4354

'reference' : initialization of reference member requires a temporary variable

There was an attempt to initialize a member that was a reference. This condition causes an error under the default /Ze command-line option.

The compiler created a temporary stack variable to perform the initialization. Since the stack variable will be eliminated after the termination of the constructor, the pointer will be invalid.

This warning may be avoided by initializing the member instead of its reference.


Compiler Warning (levels 1 and 4) C4355

'this' : used in base member initializer list

The this pointer is only valid within nonstatic member functions, but was used in the initializer list for a base class.

This is a level-1 warning when Microsoft extensions are enabled (/Ze) and a level-4 warning otherwise.


Compiler Warning (level 1) C4385

'text' the 'identifier1' in base 'identifier2'

An identifier on the line where this warning was caused cannot be distinguished from the identifier listed in this warning.

You only receive this warning when you have already received error C2385 about an ambiguity in your class hierarchy. This warning is used to provide additional information about why hierarchy is ambiguous.


Compiler Warning (level 1) C4386

'text' to the 'identifier1' in base 'identifier2'

An identifier on the line where this warning was caused cannot be unambiguously converted to the identifier listed in this warning.

You only receive this warning when you have already received error C2386 about an ambiguity in your class hierarchy. This warning is used to provide additional information about why the hierarchy is ambiguous.


Compiler Warning (level 3) C4390

';' : empty controlled statement found; is this what was intended?"

This warning will be issued when a semicolon is found after a control statement that contains no instructions.

For example, this warning catches cases like:

if (condition);      // note extra semi-colon
      statement;      // intended to execute only if <cond> is true


Compiler Warning (level 1) C4401

'identifier' : member is bit field

An attempt was made to access the given bit-field member within inline assembler code.

The identifier is a bit field. A bit-field member cannot be accessed within inline assembler code. The last packing boundary before the bit-field member was used.

To avoid this warning, cast the bit field to an appropriate type before making the reference in inline assembler code.


Compiler Warning (level 1) C4402

must use PTR operator

A type was used on an operand without a PTR operator.

The compiler assumed the PTR operator.

The PTR operator is required when referring to or casting to a type in inline assembler code.


Compiler Warning (level 1) C4403

illegal PTR operator

A PTR operator was used inappropriately in inline assembler code.

The compiler ignored the PTR operator.


Compiler Warning (level 3) C4404

period on directive ignored

The optional period preceding the directive was ignored.

This warning is informational.


Compiler Warning (level 1) C4405

'identifier' : identifier is reserved word

A reserved word was used as the name of the identifier.

Use of the identifier in this way may cause unpredictable results.

This warning can be avoided by not using reserved words as identifiers.


Compiler Warning (level 1) C4406

operand on directive ignored

The directive does not take any operands, but an operand was specified.

The compiler ignored the given operand or operands.


Compiler Warning (level 1) C4409

illegal instruction size

The instruction did not have a form with the specified size. The smallest legal size was used.

Make sure that the proper form of the instruction is being used.


Compiler Warning (level 1) C4410

illegal size for operand

One of the operands on the instruction had an incorrect size. The smallest legal size for the operand was used.

Make sure that an operand of the proper size is being used.


Compiler Warning (level 1) C4411

'identifier' : symbol resolves to displacement register

The identifier is a local symbol that resolves to a displacement register and therefore may be used on an operand with another symbol.

This warning is informational.


Compiler Warning (level 3) C4414

'function' : short jump to function converted to near

Short jumps generate a 1-byte instruction. The instruction includes a short offset that represents the distance between the jump and the function definition. The compiler must generate a special record for the jump, which requires the jmp instruction to be either NEAR or FAR, but not SHORT. The compiler made the conversion.

For example, the following code generates this warning:

main()
{
    _asm jmp SHORT main
}


Compiler Warning (level 2) C4500

'class' : class has private/protected data members; user-defined constructor advised

The given class, structure, or union contains private or protected data. As this data is unavailable to many parts of the program, a user-defined constructor should be used.


Compiler Warning (level 1) C4501

'identifier' : use of '::' unnecessary here

The given identifier was local in scope, so the scope resolution operator (::) was not required.

The compiler ignored the optional scope resolution operator.


Compiler Warning (level 1) C4502

'linkage specification' requires use of keyword 'extern' and must precede all other specifiers

A linkage was specified without the extern keyword. Linkage is not relevant to non-extern types.

The compiler assumed the extern keyword.


Compiler Warning (level 1) C4503

'identifier' : decorated name length exceeded, name was truncated

The decorated name was longer than the maximum the compiler allows (247), and was truncated. To avoid this warning and the truncation, reduce the number of arguments or name length of identifiers used.


Compiler Warning (level 4) C4504

type still ambiguous after parsing 'number' tokens, assuming declaration

The compiler could not resolve the type after looking ahead in the code.

Simplify the code to make the statement clearer. This warning can often be eliminated by using an explicit type cast to an ambiguous expression.


Compiler Warning (level 4) C4505

'function' : unreferenced local function has been removed

The given function is local and not referenced in the body of the module; therefore, the function is dead code.

The compiler did not generate code for this dead function.


Compiler Warning (level 1) C4506

no definition for inline function 'function'

The given function was declared and marked for inlining but was not defined.

The compiler did not inline the function.

Make sure that external functions to be inlined are declared with the extern keyword.


Compiler Warning (level 4) C4507

explicit linkage specified after default linkage was used

After an identifier was declared with the default C++ linkage, it was explicitly declared as having C++ linkage.

The following code generates this warning:

void   WhereProhibited( void );
extern "C++" { void   WhereProhibited( void ); };  //warning


Compiler Warning (level 1) C4508

'function' : function should return a value; void return type assumed

The given function did not specify a return type; the compiler assumed that the return type was void.

This warning can be avoided by declaring functions as void that do not return a value.


Compiler Warning (level 3) C4509

nonstandard extension used: 'function' uses SEH and 'object' has destructor

You should not use structured exception handling in functions that use objects with destructors because if an exception occurs, the object’s destructor will not be called. You might want to use C++ exception handling instead. See C++ Exception Handling Syntax for more information.


Compiler Warning (level 3) C4510

'class' : default constructor could not be generated

The compiler was unable to generate a default constructor for the given class. No constructor was created.

This warning can be caused by having a default constructor for the base class that is not accessible by the derived class. An inherited constructor from a base class with a different ambient memory model can also cause this warning.

This warning can be avoided by specifying a user-defined default constructor for the class.


Compiler Warning (level 3) C4511

'class' : copy constructor could not be generated

The compiler was unable to generate a copy constructor for the given class. No constructor was created.

This warning can be caused by having a copy constructor for the base class that is not accessible by the derived class. An inherited copy constructor from a base class with a different ambient memory model can also cause this warning.

This warning can be avoided by specifying a user-defined copy constructor for the class.


Compiler Warning (level 3) C4512

'class' : assignment operator could not be generated

The compiler was unable to generate an assignment operator for the given class. No assignment operator was created.

This warning can be caused by having an assignment operator for the base class that is not accessible by the derived class.

This warning can be avoided by specifying a user-defined assignment operator for the class.


Compiler Warning (level 3) C4513

'class' : destructor could not be generated

The compiler was unable to generate a default constructor for the given class. No constructor was created.

This warning can be caused by having an assignment operator for the base class that is not accessible by the derived class.

This warning can be avoided by specifying a user-defined destructor for the class.


Compiler Warning (level 4) C4514

unreferenced inline/local function has been removed

The optimizer removed an inline function that is not called.


Compiler Warning (level 4) C4515

'namespace' : namespace uses itself

You created a namespace that uses itself, as the following example shows:

namespace A {
   using namespace A; // warning C4515
}


Compiler Warning (level 4) C4516

'class::symbol' : access-declarations are deprecated; member using-declarations provide a better alternative

Here deprecated means the ANSI C++ committee has declared access-declarations (changing the access of a member in a derived class without the using keyword, see the example below) as outdated. You should use using-declarations because access-declarations will be removed by the committee in future versions of C++.

The following code shows class B derived from base class A.

class A {
public:
   x(char);
};

class B : protected A {
public:
   A::x;  // access-declaration, warning C4516
};

To use using-declarations, rewrite class B with the using keyword:

class B : protected A {
public:
   using A::x; // using-declaration, ok
};


Compiler Warning (level 4) C4517

access-declarations are deprecated; member using-declarations provice a better alternative

Here deprecated means the ANSI C++ committee has declared access-declarations (changing the access of a member in a derived class without the using keyword, see the example below) as outdated. You should use using-declarations because access-declarations will be removed by the committee in future versions of C++.

The following code shows class B derived from base class A.

class A {
public:
   x(char);
};

class B : protected A {
public:
   A::x;  // access-declaration, warning C4516
};

To use using-declarations, rewrite class B with the using keyword:

class B : protected A {
public:
   using A::x; // using-declaration, ok
};


Compiler Warning (level 1) C4518

'specifier' : storage-class or type specifier(s) unexpected here; ignored

For example, the following storage-class specifier locations are invalid and when compiled will cause C4518:

__declspec(dllexport) extern "C" void foo();   // Here
   class C {
      int * virtual vfunc();         // And here
   };

The following macro will not give the expected results and will result in a C4518:

extern "C" DLLEXPORT STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);

This macro should be written as:

STDAPI DLLEXPORT DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv);


Compiler Warning (level 3) C4520

'class' : multiple default constructors specified

There were multiple default constructors specified for the given class. The first constructor was used.

Make sure that there is only one default constructor defined.


Compiler Warning (level 3) C4521

'class' : multiple copy constructors specified

There were multiple copy constructors of a single type specified for the given class. The first constructor was used.

Make sure that there is only one copy constructor defined for a type.


Compiler Warning (level 3) C4522

'class' : multiple assignment operators specified

There were multiple assignment operators of a single type specified for the given class. The first constructor was used.

Make sure that there is only one assignment operator defined for a type.


Compiler Warning (level 3) C4523

'class' : multiple destructors specified

There were multiple destructors specified for the given class. The first destructor was used.

Make sure that there is only one destructor defined for a distance.


Compiler Warning (level 3) C4524

'class' : redundant use of 'friend' on destructor

The friend access specifier was given for a destructor. Since the destructor is automatically a member function of the given class, this specification is irrelevant.

The extraneous friend specifier was ignored.


Compiler Warning (level 3) C4525

'class' : redundant use of 'friend' on constructor

The friend access specifier was given for a constructor. Since the constructor is automatically a member function of the given class, this specification is irrelevant.

The extraneous friend specifier was ignored.


Compiler Warning (level 3) C4527

instances of type 'class' can never be destroyed - user-defined destructor required

The given derived class did not include a destructor, and the compiler could not generate one. The class cannot be destroyed.

This warning can be avoided by including a user-defined destructor for the given class.


Compiler Warning (level 1) C4530

C++ exception handler used, but unwind semantics are not enabled. Specify -GX

C++ exception handling was used but the Enable Exception Handling (/GX) option was not selected.

When the /GX option has not been enabled, an object with automatic storage in the frame between the function doing the throw and the function catching the throw will not be destroyed. However, an object with automatic storage created in a try or catch block will be destroyed.


Compiler Warning (level 1) C4540

dynamic_cast used to convert to inaccessible or ambiguous base; run-time test will fail ('type1' to 'type2')

You used dynamic_cast to convert from one type to another, but the compiler was able to determine that the cast would always fall (return NULL) because a base class is inaccessible (the base class is private, for instance) or ambiguous (the base class appears more than once in the class hierarchy, for instance).

The following shows an example of this warning. Class D is derived from class B. The program uses dynamic_cast to cast from class D (the derived class) to class B, which will always fail because class B is private and thus inacessible. Changing the access on B to public will fix the problem.

class B { virtual void g(); };
class D : private B {};

void a() {
   D   d;
   B*   bp;
   bp = dynamic_cast<B*>(&d); // error C4540
}


Compiler Warning (level 1) C4541

'identifier' used on polymorphic type 'type' with /GR-; unpredictable behavior may result

You did not enable run-time type information and tried to use a feature that requires run-time type information support. Recompile with the /GR switch.

For more information, see the Enable Run-Time Type Information (/GR) compiler option.


Compiler Warning (level 1) C4550

expression evaluates to a function which is missing an argument list

This error occurs when a de-referenced pointer to a function is missing an argument list. The following example generates this error:

bool f()
{
   return true;
}

typedef bool (*pf_t)();

int main()
{
   pf_t pf = f;
   if (*pf) {}   // Error
   return 0;

}


Compiler Warning (level 1) C4551

function call missing argument list

A function call in Visual C++ must include the open and close parentheses after the function name even if the function takes no parameters.

The following example will generate a C4551 warning:

void function1(){

}

main()
{
   function1;
   return 0;
}


Compiler Warning (level 1) C4552

‘operator’ : operator has no effect; did you forget something?

If an expression statement has an operator with no side-effect as the top of the expression, it's probably a mistake.

For example:

int i, j;
   i + j;

You can suppress this warning by placing parentheses around the i + j, for example (i + j).


Compiler Warning (level 1) C4553

'operator' : operator has no effect; did you intend 'operator'?

If an expression statement has an operator with no side-effect as the top of the expression, it's probably a mistake.

For example:

int i;
   i == func();   // user intended i = func();

would result in a '==' : operator has no effect; did you intend '='? warning.


Compiler Warning (level 3) C4554

'operator' : possible operator precedence error; use parentheses to avoid ambiguity

For example, the following instruction will generate a C4554 warning:

a = a << b + c;   // probably intended (a << b) + c,
                  // but will get a << (b + c)


Compiler Warnings C4610 Through C4999

The following topics cover compiler warnings C4610 through C4999.


Compiler Warning (level 1) C4610

object 'class' can never be instantiated - user-defined constructor required

The given class had neither user-defined nor default constructors; it cannot be instantiated. No instantiation was performed.

Make sure that all classes have valid user-defined or default constructors.


Compiler Warning (level 4) C4611

interaction between '_setjmp' and C++ object destruction is non-portable

On some platforms, functions that include _setjmp may not support C++ object semantics of destruction when out of scope.

To avoid unexpected behavior, avoid using _setjmp in functions that have constructors and destructors.


Compiler Warning (level 1) C4612

error in include filename

This warning can only happen with #pragma include_alias. This warning occurs when the filename is incorrect or missing.

The arguments supplied to the #pragma include_alias statement should both have the quoted form (“filename”) or the angle-bracket form (<filename>). If both forms show up in one #pragma include_alias statement, then the warning is generated.

The following example generates this warning:

#pragma include_alias("StandardIO", <stdio.h>)


Compiler Warning (level 1) C4613

'segment' : class of segment cannot be changed

There was an attempt to create a segment with the same class name as a segment used by the compiler.

No new segment class was created.

This warning is generated only when compiling 32-bit programs.


Compiler Warning (level 1) C4614

'type' : varargs parameters with this type were promoted

The compiler performed standard promotion on the arguments to a varargs function. The promotions include char-to-int and float-to-double.

If you didn't expect and don't want this promotion, use normal functions instead of varargs functions.


Compiler Warning (level 1) C4615

#pragma warning : unknown user warning type

An illegal warning type was used with the warning pragma.

Valid warning types are "1", "2", "3", "4", "default", "off", and "error".


Compiler Warning (level 1) C4616

#pragma warning : warning number 'number1' out of range, must be between 'number2' and 'number3'

The warning number that was specified in the warning pragma was not in the range of assignable warnings. Only warnings between number2 and number3 can be reassigned.

The pragma was ignored.


Compiler Warning (level 1) C4617

#pragma warning : invalid warning number

An illegal warning number was used with the warning pragma.


Compiler Warning (level 1) C4618

pragma parameters included an empty string, pragma ignored

A null string was given as an argument to a #pragma.

The pragma was processed without the argument.

The following example causes this warning:

#pragma code_seg("")    // warning
void main() {}


Compiler Warning (level 1) C4620

no postfix form of 'operator ++' found for type 'type', using prefix form

There was no postfix increment operator defined for the given type. The compiler used the overloaded prefix operator.

This warning can be avoided by defining a postfix ++ operator. This is done by creating a two-argument version of the ++ operator as shown below:

class prepost
{
public:
   prepost operator++ ()
   {
 // inline prefix routine
   };
   prepost operator++ ( int )
   {
 // inline postfix routine
   };
}


Compiler Warning (level 1) C4621

no postfix form of 'operator --' found for type 'type', using prefix form

There was no postfix decrement operator defined for the given type. The compiler used the overloaded prefix operator.

This warning can be avoided by defining a postfix -- operator. This is done by creating a two-argument version of the -- operator as shown below:

class prepost
{
public:
   prepost operator-- ()
   {
 // inline prefix routine
   };
   prepost operator-- ( int )
   {
 // inline postfix routine
   };
}


Compiler Warning (level 3) C4622

Overwriting debug information formed during creation of the precompiled header in object file: 'file'

CodeView information in the specified file was lost when it was compiled with the /Yu (Use Precompiled Headers) option selected.

Rename the object file (using the /Fo switch) when creating or using the precompiled header file, and link using the new object file.


Compiler Warning (level 1) C4630

'symbol' : 'extern' storage class specifier illegal on member definition

The given data member or member function was defined as external. Members cannot be declared as extern.

The compiler ignored the extern keyword.

Only entire objects can be made external.


Compiler Warning (level 1) C4650

debugging information not in precompiled header; only global symbols from the header will be available

The precompiled header file was not compiled with Microsoft symbolic debugging information.

When linked, the resulting executable or dynamic-link library file will not include debugging information for local symbols contained in the precompiled header.

This warning can be avoided by recompiling the precompiled header file with the /Zi command-line option.


Compiler Warning (level 1) C4651

'definition' specified for precompiled header but not for current compile

The given definition was specified when the precompiled header was generated, but not in this compilation.

The definition will be in effect inside the precompiled header, but not in the rest of the code.


Compiler Warning (level 1) C4652

compiler option 'option' inconsistent with precompiled header; current command-line option will override that defined in the precompiled header

The given command-line option differed from that given when the precompiled header (.PCH) was created. The option specified in the current command line was used.

This warning can be avoided by regenerating the precompiled header with the given command-line option.


Compiler Warning (level 2) C4653

compiler option 'option' inconsistent with precompiled header; current command-line option ignored

An option specified with the Use Precompiled Headers (/Yu) option was inconsistent with the options specified when the precompiled header was created. This compilation used the option specified when the precompiled header was created.

This warning can occur when a different value for the Pack Structures option (/Zp) was specified during compilation of the precompiled header.


Compiler Warning (level 1) C4655

'symbol' : variable type is new since the last build, or is defined differently elsewhere

You added a variable type that is new to your source code since the last successful build. Edit and Continue only supports adding a variable or changing a variable type if another variable of that data type was present in your source code during the latest build.

To remove this warning without ending the current debug session, change the variable back to its state before it produced this warning. Then select the Apply Code Changes command on the Debug menu.

To remove this warning without changing your source code, stop the current debug session by selecting Stop Debugging from the Debug menu. Select Build from the Build menu. After a successful build, you may debug the current source code.

If you did not add this variable or change its data type, look for other definitions of this variable type in your source code. You may find that one of the type definitions is different from the type definition referenced by this warning. Change one of the definitions to match the other.

This warning will always be followed by a C1092 error. For further information, see the Limitations of Edit and Continue.

This warning would be issued if, during a debug session, you removed the comments from the following program and then selected Apply Code Changes from the Debug menu:

void main() {
   // int x[10];
   int i = 0;
   i++;
   // x[0] = 1;
}


Compiler Warning (level 1) C4656

'symbol' : data type is new or has changed since the last build, or is defined differently elsewhere

You added or changed a data type, making it new to your source code since the last successful build. Adding or changing a member of a class or struct will cause this warning. Edit and Continue only supports data types that were present in your source code during the latest build.

To remove this warning without ending the current debug session, change the data type back to its state before it produced this warning. Then select the Apply Code Changes command on the Debug menu.

To remove this warning without changing your source code, stop the current debug session by selecting Stop Debugging from the Debug menu. Select Build from the Build menu. After a successful build, you may debug the current source code.

If you did not change the data type in any way, look for other definitions of this data type in your source code. You may find that one of the definitions is different from the definition referenced by this warning. Change one of the definitions to match the other.

This warning will always be followed by a C1092 error. For further information, see the Limitations of Edit and Continue.

The following code, when entered while the debugger is running, will generate this error after you click Apply Code Changes on the Debug menu.

struct bar {
int i;
} varname;


Compiler Warning (level 1) C4657

expression involves a data type that is new since the last build

You added or changed an expression to involve a data type that is new to your source code since the last successful build. Edit and Continue only supports data types that were present in your source code during the latest build.

To remove this warning without ending the current debug session, change the expression back to its state before it produced this warning. Then select the Apply Code Changes command on the Debug menu.

To remove this warning without changing your source code, stop the current debug session by selecting Stop Debugging from the Debug menu. Select Build from the Build menu. After a successful build, you may debug the current source code.

This warning will always be followed by a C1092 error. For further information, see the Limitations of Edit and Continue.


Compiler Warning (level 1) C4658

'function' : function prototype is new since the last build, or is declared differently elsewhere

You added or changed a function prototype, making its return type, parameter list, or other declaration attribute new to your source code since the last successful build. Edit and Continue only supports a new or changed function prototype if the same prototype is used by another function that was present in your source code during the latest build.

To remove this warning without ending the current debug session, change the function prototype back to its state before it produced this warning. Then select the Apply Code Changes command on the Debug menu.

To remove this warning without changing your source code, stop the current debug session by selecting Stop Debugging from the Debug menu. Select Build from the Build menu. After a successful build, you may debug the current source code.

If you did not change this function prototype, look for other declarations of this function in your source code. You may find that one of the declarations is different from the declaration referenced by this warning. Change one of the declarations to match the other.

This warning will always be followed by a C1092 error. For further information, see the Limitations of Edit and Continue.

To generate this warning, debug the following code snippet. While the debugger is running, change the return type of func1 from void to int and remove the comment in func1. Then click Apply Code Changes on the Debug menu.

void func1()
{
   int m_val = 1;
   //return m_val;
}

void main()
{
func1();
}


Compiler Warning (level 2) C4660

template-class specialization 'identifier' is already instantiated

A templated class or function was instantiated more than once.

The following example causes this warning:

template<class T, int i> class MyClass {};
template MyClass< int, 4 >;
template MyClass< int, 4 >;  // warning, second instantiation


Compiler Warning (level 1) C4661

'identifier' : no suitable definition provided for explicit template instantiation request

A member of the template class was not defined.

The following example causes this warning:

template<class T> class MyClass
{
public:
   void i();              // declaration but not definition
};
template MyClass< int >;  // warning


Compiler Warning (level 1) C4662

explicit instantiation; template-class 'identifier1' has no definition from which to specialize 'identifier2'

The specified template-class was declared, but defined.

The following example causes this warning:

template<class T, int i> class MyClass; // no definition
template MyClass< int, 1>;              // warning


Compiler Warning (level 4) C4663

C++ language change: to explicitly specialize class template 'identifier' use the following syntax:

In order to explicitly specialize a template class, use the new syntax. For example:

template<class T> class X {};
template<> class X<int> {}   //New syntax: explicitly specialize X
class X<char> {};      //old way - now illegal

Note If the compiler option /Za(Disable Language Extensions) is selected, then the compiler will generate error C2906.


Compiler Warning (level 4) C4665

C++ language change: assuming 'declaration' is an explicit specialization of a function template

The compiler assumes that the definition of a non-template function is an explicit specialization of the function template. For example:

template<class T> void f(T) {};
void f(int) {};   // assumes the user means
            // template<> void f(int);

This code generates this compiler warning.


Compiler Warning (level 1) C4666

'declaration' : function differs from 'declaration' only by calling convention

This warning occurs when the calling convention of an explicit specialization of a function template is different from that of the function template. For example:

template<class T> void __cdecl f(const T &) { }
template<> void __stdcall f(const int &) { } //warning


Compiler Warning (level 4) C4670

'identifier' : this base class is inaccessible

The specified base class of an object to be thrown in a try block is not accessible. The object cannot be instantiated if it is thrown. Check that the base class is inherited with the correct access specifier.

The following example causes this warning:

class A {};
class B : A {} b;   // inherits A with private access by default

void main()
{
    try
    {
       throw b;
    }
    catch( B )      // warning
    {
    }
}


Compiler Warning (level 4) C4671

'identifier' : the copy constructor is inaccessible

A user-defined copy constructor for the specified thrown object is not accessible. The object cannot be constructed when it is thrown. Check that the copy constructor has public access.

The following example causes this warning:

class C
{
    C( C& );    // copy constructor has private access by default
} c;

void main()
{
    try
    {
       throw c;
    }
    catch( C )    // warning
    {
    }
}


Compiler Warning (level 4) C4672

'identifier1' : ambiguous. First seen as 'identifier2'

The specified object to be thrown in a try block is ambiguous. The object cannot be disambiguated if it is thrown.


Compiler Warning (level 4) C4673

throwing 'identifier' the following types will not be considered at the catch site

A throw object cannot be handled in the catch block. Each type that cannot be handled is listed in the error output immediately following the line containing this warning. Each unhandled type has its own warning. Read the warning for each specific type for more information.


Compiler Warning (level 4) C4674

'identifier' : the destructor is inaccessible

A user-defined destructor for the specified thrown object is not accessible. The object cannot be destroyed after it is thrown. Check that the destructor has public access.

The following example causes this warning;

class C
{
    ~C();    // destructor has private access by default
} c;

void main()
{
    try
    {
       throw c;
    }
    catch( C )    // warning
    {
    }
}


Compiler Warning (level 1) C4696

/ZBvalue1 option out of range; assuming 'value2'

You used the /ZB option with value1, which is out of range, so the compiler used value2 instead.


Compiler Warning (level 4) C4699

Note: pre-compiled header usage information message

This warning provides informational messages about the status of precompiled headers.


Compiler Warning (level 1) C4700

local variable 'name' used without having been initialized

You used the local variable name without first assigning it a value, which could lead to unpredictable results.

This warning is issued only when either /Od or /Ox is specified.


Compiler Warning (level 4) C4701

local variable 'name' may be used without having been initialized

You may have used the local variable name without first assigning it a value, which could lead to unpredictable results.


Compiler Warning (level 4) C4705

statement has no effect

The indicated statement will have no effect on the program execution.

Each of these statements will generate this warning:

1;
a + 1;
b == c;


Compiler Warning (level 4) C4706

assignment within conditional expression

The test value in a conditional expression was the result of an assignment.

This warning is informational.

An assignment has a value (the value on the left side of the assignment) that can be used legally in another expression, including a test expression. However, the intention may have been to test a relation, not to make an assignment.

For example, the following line, which generates this warning, assigns b to a and compares the value of a with 0:

if ( a = b ) ...

However, the following line tests whether a and b are equal:

if ( a == b ) ...


Compiler Warning (level 4) C4709

comma operator within array index expression

The value used as an index into an array was the last one of multiple expressions separated by the comma operator.

An array index legally may be the value of the last expression in a series of expressions separated by the comma operator. However, the intent may have been to use the expressions to specify multiple indexes into a multidimensional array.

For example, the following line, which generates this warning, is legal in C and specifies the index c into array a:

a[b,c]

However, the following line uses both b and c as indexes into a two-dimensional array:

a[b][c]

The following examples generate this warning:

p = new int [2,3];   //C4709
delete[2,4] p;      //C4709

In the following example multiple warnings are generated:

a[i,j]=a[i, a[i,j]]


Compiler Warning (level 4) C4710

'function' : function not inlined

The given function was selected for inline expansion, but the compiler did not perform the inlining.

Inlining is performed at the compiler's discretion. The inline keyword, like the register keyword, is used as a hint for the compiler. The compiler uses heuristics to determine if it should inline a particular function to speed up the code when compiling for speed, or if it should inline a particular function to make the code smaller when compiling for space. The compiler will only inline very small functions when compiling for space.

In some cases, the compiler will not inline a particular function for mechanical reasons. See C4714 for a list of reasons the compiler may not inline a function.


Compiler Warning (level 1) C4711

function 'function' selected for inline expansion

The compiler performed inlining on the given function, although it was not marked for inlining by the user.

Inlining is performed at the compiler's discretion. This warning is informational.


Compiler Warning (level 2) C4712

'symbol' : used as register - loss of debugging information

The given symbol was based on another symbol that was converted to a register, thereby losing debugging information.

This warning can be avoided by not using the /Oe Register-Allocation command-line option.


Compiler Warning (level 1) C4713

internal compiler error: restartable

Note This message is only a warning. The resulting code should be perfectly correct and safe, but is not optimized.

This error is only emitted by the optimizing compiler when it detects a problem while generating code in Pass 2. In these cases the problem has been detected at a point which allows the compiler to restart the code-generation process for the function where the error was detected. The compiler turns off optimizations for this function and regenerates the code. Note that optimizations are turned off only for the particular function, not for the entire module.

Tips

  • If you wish to maximize the optimization used in the function that is causing the warning, you can determine which option is at fault by removing options one at a time and recompiling until the message goes away. Generally the last one removed is causing the problem and all other optimizations can be used safely. The options that most commonly cause this warning are /Oe, /Oi, /Ol, and /Oa.

    Once the offending optimization is discovered, it need not be turned off for the entire compilation. The offending optimization can be disabled with the optimize pragma while compiling the function where the error occurred, but enabled for the rest of the module.

  • It is rare, but such errors can occur at very low optimization levels or even when optimization is disabled. In such cases rewriting the line where the error is reported (or possibly several lines, including the one causing the error) may be a solution.

  • If none of these options works, contact Microsoft Product Support Services for help.

In all cases of internal compiler errors, restartable or not, report the problem to Product Support Services, providing a test case and the options used. Include the full text of the error message, including the module and line number of the compiler file which is given in the second line of the error message. This will allow Microsoft to find and fix the underlying problem for future versions of the compiler.


Compiler Warning (level 1) C4714

'function' : function marked as __forceinline not inlined

The given function was selected for inline expansion, but the compiler did not perform the inlining.

Although __forceinline is a stronger indication to the compiler than __inline, inlining is still performed at the compiler's discretion, but no heuristics are used to determine the benefits from inlining this function.

In some cases, the compiler will not inline a particular function for mechanical reasons. For example, the compiler will not inline:

  • A function if it would result in mixing both SEH and C++ EH.

  • Some functions with copy constructed object passed by value when -GX/EHs/EHa is on.

  • Functions returning an unwindable object by value when -GX/EHs/EHa is on.

  • Functions with inline assembly when compiling without -Og/Ox/O1/O2.

  • Functions with variable argument list.


Compiler Warning (level 1) C4715

'function' : not all control paths return a value

The specified function can potentially not return a value.

The following example generates this warning:

int func1( int i )
{
   if( i )
   return 3;  // warning, nothing returned if i == 0
}

To prevent this warning, modify the code so that all paths assign a return value to the function:

int func1( int i )
{
   if( i ) return 3;
   else return 0;     // OK, always returns a value
}

It is possible that your code may contain a call to a function that never returns, as in the following example:

int glue()
{
   if(...)
     return 1;
   else if(...)
     return 0;
   else
     fatal();
}

This code also generates an warning, because the compiler does not know that fatal never returns. To prevent this code from generating an error message, declare fatal using __declspec(noreturn).


Compiler Warning (level 1) C4716

'function' must return a value

The given function did not return a value.

Only functions with a return type of void can use the return command without an accompanying return value.

An undefined value will be returned when this function is called.


Compiler Warning (level 2) C4720

'initializing' : do not initialize a non-const 'type1' with a non-lvalue 'type2' function return

A nonconst T& was initialized with the value of a function call which returns T. This is an error, because a function call is not an l-value (unless it returns a reference) and a nonconst T& must be initialized with a T l-value. However, when Microsoft extensions have been enabled (/Ze), Visual C++ renders this as a warning because the construction is harmless and because the construction occurs fairly frequently in existing code.

The can be eliminated by changing the reference being initialized to a const T&. The following example causes this warning:

struct X {};
X f();
X&r = f();  // warning


Compiler Warning (level 3) C4723

potential divide by 0

The second operand in a divide operation evaluated to zero at compile time, giving undefined results.

The zero operand may have been generated by the compiler, as in the following example:

int    i, j, k = 42;
i /= ( j && k );


Compiler Warning (level 3) C4724

potential mod by 0

The second operand in a remainder operation evaluated to zero at compile time, giving undefined results.


Compiler Warning (level 3) C4725

instruction may be inaccurate on some Pentiums

Your code contains an inline assembly instruction that may not produce accurate results on some Pentium microprocessors.


Compiler Warning (level 1) C4726

'option' : unknown memory-model command-line option

The character (or characters) used with the /A option was not recognized as a valid memory-model specifier.

The option was ignored.


Compiler Warning (level 4) C4727

conditional expression is constant

The controlling expression of an if statement or while loop evaluated to a constant.

As a result, the code in the body of the if statement or while loop either always executes or never executes.

This warning is informational.


Compiler Warning (level 1) C4728

attempt to take address of function identifier produces address of jump table entry

Your code contains a statement or expression that tries to refer to the address of a function by taking the address of the function's identifier. When you take the address of a function you get the address of the jump table entry for the function, not the address of the function itself.

As an example of this condition, consider this code fragment:

void func(void) {}
   .
   .
   .
int in_func(char *ptr)
{
   if (ptr > (char *)&func && ptr < (char *)&func + 40)
   {
      // erroneously expects that ptr points within func()
      return 1;
   }

   return 0;
}

Within the expression:

   (ptr > (char *)&func && ptr < (char *)&func + 40)

the result of &func is the address of the jump table entry for func(), not the address of func() itself. Hence the expression does not determine whether or not ptr is within the first 40 bytes of func(); but instead determines whether or not ptr is within the 40 bytes following the jump table entry for func(), which is not what was intended.


Compiler Warning (level 1) C4741

/Oq option ignored for __fastcall function 'function'

The fastcall and saveregs calling conventions are not allowed for p-code functions. The function was compiled into native code.

This warning can be avoided by using a different calling convention or by turning p-code generation off during the definition of fastcall and saveregs functions, as in:

#pragma optimize( "q", off )    //Turn p-code on
int __fastcall FastFunc( void )
  {...};
#pragma optimize( "q" )       //Return to default p-code mode


Compiler Warning (level 2) C4756

overflow in constant arithmetic

The compiler generated an exception while doing constant arithmetic during compilation.

For example:

float fp_val = 1.0e100;

In this example, the floating-point constant 1.0e100 exceeds the maximum allowable value for a double-precision data item.


Compiler Warning (level 1) C4761

integral size mismatch in argument : conversion supplied

The base types of the actual and formal parameters of a function were different.

The compiler converted the actual parameter to the type of the formal parameter.


Compiler Warning (level 2) C4763

'function' : function too large for postoptimizer

Not enough space was available to optimize the given function.

One of the following may be a solution:

  • Divide the function into two or more smaller functions.

  • Recompile with fewer optimizations.


Compiler Warning (level 2) C4765

recoverable heap overflow in postoptimizer

The postoptimizing pass ran out of memory but was able to recover. Some optimization options may have been ignored.

One of the following may be a solution:

  • Divide the function into two or more smaller functions.

  • Recompile with fewer optimizations.


Compiler Warning (level 2) C4766

local symbol-table overflow

Since the listing generator ran out of heap space for local variables, the source listing may not contain symbol-table information for all local variables.

One of the following may be a solution:

  • Divide the function into two or more smaller functions.

  • Recompile with fewer optimizations.


Compiler Warning (level 1) C4773

scoping too deep; deepest scoping merged when debugging

Declarations appeared at a static nesting level greater than 16. As a result, all declarations beyond this level will seem to appear at the same level when being viewed by the debugger.


Compiler Warning (level 1) C4784

cannot initialize code-based pointer to 'identifier' in small model - generating large model

You're trying to statically initialize a code-based pointer when compiling with a small memory model (using the /AS option).

To avoid this warning, compile with a medium, compact, or large memory model (using the /AM, /AC, or /AL options, respectively), or dynamically initialize the problem pointer.

Here's an example of the type of statement that can cause this problem:

__declspec(allocate("_CODE")) int *p = &i ;

The above example could be fixed by replacing the statement with the following:

__declspec(allocate("_CODE")) int *p ;
main() {
   p = &i ;
   .
   .
   .
}


Compiler Warning (level 1) C4786

'identifier' : identifier was truncated to 'number' characters in the debug information

The identifier string exceeded the maximum allowable length and was truncated.

The debugger cannot debug code with symbols longer than 255 characters. In the debugger, you cannot view, evaluate, update, or watch the truncated symbols.

This limitation can be overcome by shortening identifier names. The example code below demonstrates this method.

A trace mechanism can also be used to solve this problem. A trace mechanism is like the printf statements in the code. It keeps track of what is going on in an application during the debugging process. The _ASSERT, _ASSERTE, _RPTn and _RPTFn macros provide concise and flexible ways to perform the trace. These macros are not defined when _DEBUG is not defined. See Using Macros for Verification and Reporting for more information.

The example below demonstrates a situation that would cause this compiler warning to occur, and the solution to this problem.

 //sample1.cpp
 //In this program we have a class of a very long name.
 //We instantiate an object of that class type. We will
 //get multiple C4786 warnings.  The comments below
 //demonstrate the solution to this problem.

 #define a_really_long_class_name a_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really_really//_really_long_class_name

 //SOLUTION: Uncomment the lines below

 //#ifdef _DEBUG
 //#define a_really_long_class_name A_SHORT_CLASS_NAME
 //#endif

 class a_really_long_class_name
 {
 public:
   a_really_long_class_name() {};
   int m_data;
 };

 void main()
 {
    a_really_long_class_name test_obj;
    test_obj.m_data = 12;
 }

The following example demonstrate that templates with some long class names as their parameters can easily exceed the 255 character limit. Solutions to the problem are also provided.

 //sample2.cpp
 //SOLUTION1: uncomment the next 4 lines
 //#ifdef _DEBUG
 //#define VeryLongClassNameA A
 //#define VeryLongClassNameB B
 //#endif

 //SOLUTION2: An alternative solution:
 //uncomment the next 3 lines.
 //#ifdef _DEBUG
 //#define SomeRandomClass SRC
 //#endif

 template <class A1, class A2, class A3, class A4>
 class VeryLongClassNameA{};

 template <class B1, class B2, class B3>
 class VeryLongClassNameB{};

 template <class C1, class C2>
 class VeryLongClassNameC{};

 template <class D1>
 class VeryLongClassNameD{};

 class SomeRandomClass{};

 typedef VeryLongClassNameD<SomeRandomClass> ClassD ;
 typedef VeryLongClassNameC<SomeRandomClass, ClassD> ClassC;
 typedef VeryLongClassNameB<SomeRandomClass, ClassC, ClassD> ClassB;
 typedef VeryLongClassNameA<SomeRandomClass, ClassB, ClassC, ClassD> ClassA;

 void SomeRandomFunction(ClassA aobj){}

 void main()
 {
   ClassA AObj ;
   SomeRandomFunction(AObj) ;
 }


Compiler Warning (level 1) C4788

'identifier' identifier was truncated to 'number' characters

Only the first 31 characters of an identifier are significant in C. In Visual C++, the first 255 characters (after name decoration) are significant. The characters after the limit were truncated.

This may mean that two identifiers that are different before truncation may have the same identifier name after truncation.

The debugger cannot debug code with symbols longer than 255 characters. In the debugger, you cannot view, evaluate, update, or watch the truncated symbols.

This limitation can be overcome by shortening identifier names. Please see compiler warning C4786 for examples that demonstrate the solution to this problem.

A trace mechanism can also be used to solve this problem. A trace mechanism is like the printf statements in the code. It keeps track of what is going on in an application during the debugging process. The _ASSERT, _ASSERTE, _RPTn and _RPTFn macros provide concise and flexible ways to perform the trace. These macros are not defined when _DEBUG is not defined. See Using Macros for Verification and Reporting for more information.


Compiler Warning (level 2) C4790

insufficient memory to process debugging information

The program was compiled with the /Zi option, but not enough memory was available to create the required debugging information.

One of the following may be a solution:

  • Split the current file into two or more files and compile them separately.

  • Remove other programs or drivers running in the system that could be consuming significant amounts of memory.


Compiler Warning (level 2) C4791

loss of debugging information caused by optimization

Some optimizations, such as code motion, cause references to nested variables to be moved. The information about the level at which the variables are declared may be lost. As a result, all declarations will seem to be at nesting level 1.

This warning can be eliminated by turning off the optimization options for debugging purposes.


Compiler Warning (level 1) C4792

long double type not supported by alternate math library

The long double numeric type is not supported by the /FPa alternate math emulation library. This can cause unresolved external errors from the linker.

This warning can be avoided by using another emulation library (such as /FPi) or by avoiding the long double type.

Ignore this warning if a special handler for the long double type is included in the link process.


Compiler Warning (level 1) C4798

native code generated for p-code function ‘function’ with exception handler or unwind semantics

P-code doesn’t support structured exception handling, C++ exception handing, or unwind semantics so the compiler generated native code for function.


Compiler Warning (level 1) C4799

function 'function' has no EMMS instruction

The function has at least one MMX instruction, but doesn't have an EMMS instruction. When a multimedia instruction is used, an EMMS instruction should also be used to clear the multimedia tag word at the end of the MMX code.

For related information, see the Intel’s MMX Instruction Set.


Compiler Warning (level 3) C4800

'type' : forcing value to bool 'true' or 'false' (performance warning)

This warning is generated when some non-bool value is assigned or coerced into type bool. Typically, this message is caused by assigning int variables to bool variables where the int variable contains only values true and false, and could be redeclared as type bool. If you cannot rewrite the expression to use type bool, then you can add "!=0" to the expression, which gives the expression type bool. Casting the expression to type bool will not disable the warning, which is by design.


Compiler Warning (level 1) C4804

'operation' : unsafe use of type 'bool' in operation

This warning is for unary operations and is generated when you used a bool variable or value in an unexpected way. For example, if you use operators such as the negative unary operator (-) or the complement operator (~).


Compiler Warning (level 1) C4805

'operation' : unsafe mix of type 'type' and type 'type' in operation

This message is similar to C4804, and it is limited to binary operations. It is generated for operations such as b &= i, b+=i, b/=b, b%=i, etc., where b and i are bool and int respectively .


Compiler Warning (level 1) C4806

'operation' : unsafe operation: no value of type 'type' promoted to type 'type' can equal the given constant

This message warns against serious errors such as b == 3, where b has type bool. The promotion rules cause bool to be promoted to int. This is legal according to the ANSI C++ Working Paper, but it can never be true.


Compiler Warning (level 1) C4807

'operation' : unsafe mix of type 'type' and signed bitfield of type 'type'

This warning is generated when comparing a one-bit signed bit field to a bool variable. Since a one-bit signed bit field can only contain the values -1 or 0, it is dangerous to compare it to bool. No warnings are generated about mixing bool and one-bit unsigned bitfields since they are identical to bool and can only hold 0 or 1.


Compiler Warnings (level 1) C4808

case 'value' is not a valid value for switch condition of type 'bool'

This warning occurs if a switch condition is of type bool and one of the case values is outside the range of bool (that is, true and false). Only true, false, 1, 0, and default are valid case values if the switch condition is of type bool.


Compiler Warning (level 1) C4809

switch statement has redundant 'default' label; all possible 'case' labels are given

This message is generated in places where you have both 'true' and 'false' cases in addition to a default label.


Compiler Warning (level 1) C4900

intermediate language mismatch between 'tool1' version 'version1' and 'tool2' version 'version2'

The intermediate language used in tool1 and tool2 did not match. Check that the most current version of each tool has been installed.


Compiler Warning (level 1) C4901

'register' : too many formal parameters specified

You gave too many argumentRegisters with the MPW #pragma parameter preprocessor directive.


Compiler Warning (level 1) C4902

'register' : register already used once in this list

You used an argumentRegister more than once with the MPW #pragma parameter preprocessor directive.


Compiler Warning (level 1) C4903

'register' : is not a valid register in this context

You used an invalid register with the MPW #pragma parameter preprocessor directive.


Compiler Warning (level 1) C4904

'function' : function previously seen with a different register list

You already defined function elsewhere with the MPW #pragma parameter preprocessor directive and a different register list.


Compiler Warning (level 1) C4999

UNKNOWN WARNING
From the Help menu choose the Technical Support command
or open the Technical Support help file for more information

Note the circumstances of the warning, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Compiler Errors when Implementing a CObject-Derived Class

When you implement a class derived from CObject and your code is written so that the copy constructor or assignment operator for the class needs to be called, the compiler may report errors similar to the following:

error C2660: 'CSample::CSample' : function does not take 1 parameters

error C2582: 'CSample' : 'operator =' function is unavailable

You can reproduce the problem by compiling the example in the Sample Code section below.

Note The sample code shown in this article generates the following error messages:
error C2558: 'CSample::CSample' : no copy constructor available
error C2582: 'CSample' : 'operator =' function is unavailable

The reason for the compiler errors is that CObject declares a private copy constructor and assignment operator in the AFX.H file. Because of this, the compiler does not generate a default copy constructor and assignment operator for the CObject-derived class . Because the compiler does not find these functions declared in the class, it reports the errors.

To avoid the compiler errors, you need to implement a copy constructor and assignment operator for the CObject-derived class. This is illustrated in the sample code below. You can avoid the errors by uncommenting the lines indicated in the sample code.

Sample Code

/* Compile options needed: /c
*/

// replace with #define _CONSOLE when compiling for Windows NT
#define _DOS

#include <afx.h>

class CSample : public CObject
{
private:
    short m_nValue;
public:
// uncomment the lines below to avoid the compiler errors
//    CSample() {}
//    CSample( const CSample &s )  // copy ctor
//        { m_nValue = s.m_nValue; }
//    CSample& operator=( const CSample &s )  // assignment operator
//        { m_nValue = s.m_nValue; return *this; }
};

void main()
{
    CSample a;
    CSample b = a;
    a = b;
}


Edit and Continue Errors and Warnings

The following topics describe the errors and warnings generated by the Edit and Continue feature.


Edit and Continue Error ENC1001

Cannot update thunk for symbol: symbol (loc: location, thunk: address)

An internal error has prevented Edit and Continue from applying code changes. You must stop debugging and build before code changes will take effect.


Edit and Continue Error ENC1002

Data symbol has changed: symbol (symbol)

An internal error has prevented Edit and Continue from applying code changes. You must stop debugging and build before code changes will take effect.


Edit and Continue Error ENC1003

Cannot map thunk for new function: function

An internal error has prevented Edit and Continue from applying code changes. You must stop debugging and build before code changes will take effect..


Edit and Continue Error ENC1004

Cannot open PDB for type packing: pdb (pdb)

An internal error has prevented Edit and Continue from applying code changes. You must stop debugging and build before code changes will take effect.


Edit and Continue Error ENC1005

Symbol was renamed, removed, or modified: symbol

This error can occur if you apply code changes or use Automatic Edit and Continue after one of the following changes:

  • Removing a function

  • Renaming a function

  • Changing a function prototype (arguments, calling convention, or return value)

  • Renaming a global or static variable

Edit and Continue does not work with these changes. For more information, see Limitations of Edit and Continue.


Edit and Continue Error ENC1006

A global or static variable was added, renamed, removed, or changed data type or initialization

This error can occur if you apply code changes or use Automatic Edit and Continue after one of these changes:

  • Adding a new global or static variable

  • Renaming a global or static variable

  • Removing a global or static variable

  • Changing the data type of a global or static variable

  • Changing the initialization of a global or static variable

Edit and Continue does not support these code changes. For more information, see Limitations of Edit and Continue.


Edit and Continue Error ENC1500

Edit and Continue does not support the latest code changes; build required

Edit and Continue does not support one or more of the changes made in your code. You must stop debugging and build your code before changes can be applied. For more information, see Limitations of Edit and Continue.


Edit and Continue Error ENC1501

Cannot complete Edit and Continue

Because of the conditions displayed in the Output window, Edit and Continue could not apply code changes in any of the edited files. This may occur because all of the code changes were in files that Edit and Continue cannot update, such as read-only files, statically linked libraries, or mismatched object files. For more information, see Limitations of Edit and Continue.


Edit and Continue Error ENC 1503

Code changes affect too many files; build required.

Edit and Continue cannot handle changes to more than 50 files at a time.


Edit and Continue Error ENC2001

Edit and Continue Warning ENC2001

Cannot find local variable: symbol (symbol)

Edit and Continue cannot update a function on the call stack because code changes have removed a variable that requires construction/destruction. Debugging of the function will continue with old code. Code changes will be applied the next time the function is called.


Edit and Continue Error ENC2002

Edit and Continue Warning ENC2002

New local variable requires construction or destruction: symbol (symbol)

Edit and Continue cannot update a function on the call stack because code changes have added a variable that requires construction/destruction. Debugging of the function will continue with old code. Code changes will be applied the next time the function is called.


Edit and Continue Warning ENC2003

Code position change may cause exception handling or variable destruction errors: function

The function was compiled for exception handling (/GX). Code changes before the point of execution may have altered the exception-handling state. Changes to the exception-handling state can be caused by:

  • The execution of a constructor

  • The execution of a destructor

  • Entry into a try/catch block

  • Exiting from a try/catch block

If the exception-handling state has changed, the exception handler may not be invoked and variables may not be properly constructed or destructed. You can continue debugging, but your application may crash or experience memory leaks if an exception occurs.


Edit and Continue Error ENC2004

Edit and Continue Warning ENC2004

Cannot handle adding or removing a local variable with a name that is already defined more than once: symbol (symbol)

Code changes include the addition or removal of a variable with a name that is already defined more than once (in different scopes). Edit and Continue cannot insert or delete such variables. Debugging of the function will continue with old code. Code changes will be applied the next time the function is called.


Edit and Continue Warning ENC2005

New source contributes to code. The debugger's line number information may be affected: function (function).

Code changes involve a source file that was not referenced in the latest build. This affects some debugger features while you are debugging the newly-referenced source file. It prevents you from setting breakpoints in the code or using Run To Cursor, for example. All debugger features are available for other source files. To restore full debugger features for all source files, stop debugging and build.


Edit and Continue Warning ENC2501

Edit and Continue Warning ENC2500

Cannot create filename.

Edit and Continue could not create an intermediate file. This may be due to lack or disk space or lack of write privileges.


Edit and Continue Warning ENC2501

The executable was relinked in its original build location (location), but not relinked in the location from which it was debugged (location)

The location from which the application was being debugged was not the same as the build location. Edit and Continue updates the executable in the build location only.


Edit and Continue Warning ENC2502

module is linked from a library and is not eligible for Edit and Continue

Code changes involve a module linked from a static library. Edit and Continue does not support changes to code in libraries (except DLLs).


Edit and Continue Warning ENC2503

Cannot find module

Edit and Continue cannot find a module required for your application, perhaps because the application was built on another machine. To use Edit and Continue, you must build and debug on the same machine.


Edit and Continue Warning ENC2504

Mismatch between object file and corresponding executable

The object file is newer than the executable. Edit and Continue cannot complete the code changes. You must stop debugging and build before code changes will take effect.


Edit and Continue Warning ENC2505

Ignoring changes made to source file.

Because of the conditions listed in the Output window, Edit and Continue cannot apply code changes. You must stop debugging and build before code changes will take effect.


Edit and Continue Warning ENC2506

Program execution did not proceed. (Reason: explanation)

Edit and Continue did not proceed with program execution for the reason given. Verify that the point of execution is correct, reset any disabled breakpoints, and continue debugging.


Edit and Continue Warning ENC2507

Cannot apply code changes to one or more functions on the call stack

Edit and Continue cannot apply code changes to specific functions on the call stack. Code changes will be applied the next time these functions are called. Until the functions exit, source-code debugging is not available. They can still be debugged in the Disassembly window.


Expression Evaluator Errors CXX0000 through CXX0072

The following topics cover errors CXX0000 through CXX0072.


Expression Evaluator Error CXX0000

no error condition

No error has occurred, and this message should not appear.

You can continue debugging normally.

Note the circumstances of the error and notify Microsoft Product Support Services.

This error is identical to CAN0000.


Expression Evaluator Error CXX0001

exception executing user function

The code being executed caused a general protection fault.

This error is identical to CAN0001.


Expression Evaluator Error CXX0002

error accessing user memory

The expression attempts to reference memory that is not allocated to the program being debugged.

This error is identical to CAN0002.


Expression Evaluator Error CXX0003

internal error in expression evaluator

The expression evaluator encountered an internal error.

Note the circumstances of the error and notify Microsoft Corporation by following the instructions in the Microsoft Product Assistance Request form at the back of one of your manuals.

This error is identical to CAN0003.


Expression Evaluator Error CXX0004

syntax error

The syntax of the expression is incorrect.

Retype the expression with the correct syntax.

This error is identical to CAN0004.


Expression Evaluator Error CXX0005

operator not supported

An unsupported C operator was specified in an expression.

You can usually write an equivalent expression using the supported C operators.

This error is identical to CAN0005.


Expression Evaluator Error CXX0006

missing left parenthesis

Unbalanced parentheses were found in the expression.

Retype the expression with balanced parentheses.

This error is identical to CAN0006.


Expression Evaluator Error CXX0007

missing right parenthesis

Unbalanced parentheses were found in the expression.

Retype the expression with balanced parentheses.

This error is identical to CAN0007.


Expression Evaluator Error CXX0008

missing " at end of string

The double quotation mark (") expected at the end of the string literal was missing.

Retype the expression, enclosing the string literal in double quotation marks.

This error is identical to CAN0008.


Expression Evaluator Error CXX0009

missing ' after character constant

The single quotation mark (') expected at the end of the character constant was missing.

Retype the expression, enclosing the character constant in single quotation marks.

This error is identical to CAN0009.


Expression Evaluator Error CXX0010

missing left bracket

The expression contains unbalanced square brackets.

Retype the expression with balanced square brackets.

This error is identical to CAN0010.


Expression Evaluator Error CXX0011

missing right bracket

The expression contains unbalanced square brackets.

Retype the expression with balanced square brackets.

This error is identical to CAN0011.


Expression Evaluator Error CXX0012

missing left curly brace

The expression contains an unbalanced curly brace.

Retype the expression with balanced curly braces.

This error is identical to CAN0012.


Expression Evaluator Error CXX0013

missing operator

An operator was expected in the expression but was not found.

Check the syntax of the expression.

This error is identical to CAN0013.


Expression Evaluator Error CXX0014

missing operand

An operator was specified without a required operand.

Check the syntax of the expression.

This error is identical to CAN0014.


Expression Evaluator Error CXX0015

expression too complex (stack overflow)

The expression entered was too complex or nested too deeply for the amount of storage available to the C expression evaluator.

Overflow usually occurs because of too many pending calculations.

Rearrange the expression so that each component of the expression can be evaluated as it is encountered, rather than having to wait for other parts of the expression to be calculated.

Break the expression into multiple commands.

This error is identical to CAN0015.


Expression Evaluator Error CXX0016

constant too big

The C expression evaluator cannot accept an unsigned integer constant larger than 4,294,967,295 (0FFFFFFFF hexadecimal), or a floating-point constant whose magnitude is larger than approximately 1.8E+308.

This error is identical to CAN0016.


Expression Evaluator Error CXX0017

symbol not found

A symbol specified in an expression could not be found.

One possible cause of this error is a case mismatch in the symbol name. Because C and C++ are case-sensitive languages, a symbol name must be given in the exact case in which it is defined in the source.

This error can occur when trying to typecast a variable in order to watch the variable during debugging. The typedef declares a new name for a type, but it does not define a new type. The typecast attempted in the debugger requires the name of a defined type.

Tips

  • Make sure the symbol is already declared at the point in the program where it is being used.

  • Use an actual type name to cast variables in the debugger, rather than a typedef defined name.

This error is identical to CAN0017.


Expression Evaluator Error CXX0018

bad register name

A specified register does not exist or cannot be displayed.

The Watch window can display the following registers:

AX SP DS IP

BX BP ES FL

CX SI SS GS

DX DI CS SS

EAX ESP DS EIP

EBX EBP ES EFL

ECX ESI FS

EDX EDI CS

This error is identical to CAN0018.


Expression Evaluator Error CXX0019

bad type cast

The C expression evaluator cannot perform the type cast as written.

One of the following may have occurred:

  • The specified type is unknown.

  • There were too many levels of pointer types.

For example, the type cast

(char **)h_message

cannot be evaluated by the C expression evaluator.

This error is identical to CAN0019.


Expression Evaluator Error CXX0020

operand types bad for this operation

An operator was applied to an expression with an invalid type for that operator.

For example, it is not valid to take the address of a register, or subscript an array with a floating-point expression.

This error is identical to CAN0020.


Expression Evaluator Error CXX0021

struct or union used as scalar

A structure or union was used in an expression, but no element was specified.

When manipulating a structure or union variable, the name of the variable may appear by itself, without a field qualifier. If a structure or union is used in an expression, it must be qualified with the specific element desired.

Specify the element whose value is to be used in the expression.

This error is identical to CAN0021.


Expression Evaluator Error CXX0022

function call before _main

The C expression evaluator cannot evaluate a function before the debugger has entered the function _main. The program is not properly initialized until _main has been called.

This error is identical to CAN0022.


Expression Evaluator Error CXX0023

bad radix

The radix specified is not recognized by the C expression evaluator. Only decimal, hexadecimal, and octal radixes are valid.

This error is identical to CAN0023.


Expression Evaluator Error CXX0024

operation needs l-value

An expression that does not evaluate to an l-value was specified for an operation that requires an l-value.

An l-value (so called because it appears on the left side of an assignment statement) is an expression that refers to a memory location.

For example, buffer[count] is a valid l-value because it points to a specific memory location. The logical comparison zed != 0 is not a valid l-value because it evaluates to TRUE or FALSE, not to a memory address.

This error is identical to CAN0024.


Expression Evaluator Error CXX0025

operator needs struct/union

An operator that takes an expression of struct or union type was applied to an expression that is not a struct or union.

Components of class, structure, or union variables must have a fully qualified name. Components cannot be entered without full specification.

This error is identical to CAN0025.


Expression Evaluator Error CXX0026

bad format string

A format string was improperly specified.

Check the syntax of the expression.

This error is identical to CAN0026.


Expression Evaluator Error CXX0027

tp addr not l-value

Check the syntax of the expression.

This error is identical to CAN0027.


Expression Evaluator Error CXX0028

not struct/union element

An expression of the form 'Struct.Member' or 'pStruct->Member' was specified, but <member> is not an element of the structure.

The expression may not be parenthesized correctly.

This error is identical to CAN0028.


Expression Evaluator Error CXX0029

not struct pointer

The member-selection operator (->) was applied to an expression that is not a pointer to a structure.

Check that the entire expression is parenthesized correctly, or type cast the address expression to the appropriate structure pointer type.

This error is identical to CAN0029.


Expression Evaluator Error CXX0030

expression not evaluatable

The debugger’s expression evaluator could not obtain a value for the expression as written. One likely cause is that the expression refers to memory that is outside the program’s address space (dereferencing a null pointer is one example). Windows NT and Windows 95 do not allow access to memory that is outside of the program’s address space.

You may want to rewrite your expression using parentheses to control the order of evaluation.

This error is identical to CAN0030.


Expression Evaluator Error CXX0031

expression not expandable

The expression evaluator encountered an internal error.

You may be able to write an equivalent expression that can be evaluated correctly.

This error is identical to CAN0031.


Expression Evaluator Error CXX0032

divide by 0

The expression contains a divisor of zero, which is illegal. This divisor may be the literal number zero, or it may be an expression that evaluates to zero.

This error is identical to CAN0032.


Expression Evaluator Error CXX0033

error in OMF type information

The executable file did not have a valid OMF (Object Module Format) for debugging.

One of the following may have occurred:

  • The executable file was not created with the linker released with this version of Visual C++. Relink the object code using the current version of LNK.EXE.

  • The .EXE file may have been corrupted. Recompile and relink the program.

  • This error is identical to CAN0033.


Expression Evaluator Error CXX0034

types incompatible with operator

The operand types specified are not legal for the operation.

For example, a pointer cannot be multiplied by any value.

You may need to type cast the operands to a type compatible with the operator.

This error is identical to CAN0034.


Expression Evaluator Error CXX0036

bad context {...} specification

This message can be generated by any of several errors in the use of the context operator ({}).

  • The syntax of the context operator ({}) was given incorrectly.

    The syntax of the context operator is:

    {function,module,dll}expression

    This specifies the context of expression. The context operator has the same precedence and usage as a type cast.

    Trailing commas can be omitted. If any of function, module, or dll contains a literal comma, you must enclose the entire name in parentheses.

  • The function name was spelled incorrectly, or does not exist in the specified module or dynamic-link library.

    Because C is a case-sensitive language, function must be given in the exact case as it is defined in the source.

  • The module or DLL could not be found.

    Check the full path name of the specified module or DLL.

This error is identical to CAN0036.


Expression Evaluator Error CXX0037

out of memory

The C expression evaluator ran out of memory evaluating the expression.

This error is identical to CAN0037.


Expression Evaluator Error CXX0038

function argument count and/or type mismatch

The function call as specified does not match the prototype for the function.

Retype the call with the correct number of arguments. Type cast each argument to match the prototype, as necessary.

This error is identical to CAN0038.


Expression Evaluator Error CXX0039

symbol is ambiguous

The C expression evaluator cannot determine which instance of a symbol to use in an expression. The symbol occurs more than once in the inheritance tree.

You must use the scope resolution operator (::) to explicitly specify the instance to use in the expression.

This error is identical to CAN0039.


Expression Evaluator Error CXX0040

function requires implicit conversion

Implicit conversions involving constructor calls are not supported by the C expression evaluator.

This error is identical to CAN0040.


Expression Evaluator Error CXX0041

class element must be static member or member function

A nonstatic member of a class (or structure or union) was used without specifying which instantiation of the class to use.

Only static data members or member functions can be used without specifying an instantiation.

This error is identical to CAN0041.


Expression Evaluator Error CXX0042

bad line number

This error should never occur.

Note the circumstances of the error and notify Microsoft Corporation by following the instructions in the Microsoft Product Assistance Request form at the back of one of your manuals.

This error is identical to CAN0042.


Expression Evaluator Error CXX0043

this pointer used outside member function

The this pointer can only be used for nonstatic member functions.

This error is identical to CAN0043.


Expression Evaluator Error CXX0044

use of _based(void) pointer requires :> operator

A pointer based on void cannot be used directly. You must form a complete pointer using the :> operator.

This error is identical to CAN0044.


Expression Evaluator Error CXX0045

not a function

An argument list was supplied for a symbol in the program that is not the name of a function.

For example, this error is generated for the expression

queue( alpha, beta )

when queue is not a function.

This error is identical to CAN0045.


Expression Evaluator Error CXX0046

argument list required for member function

An expression called a member function but did not specify any actual parameters.

This error is identical to CAN0046.


Expression Evaluator Error CXX0047

argument list does not match a function

An expression called a function with an actual parameter list that did not match the formal parameter list of any function with the same name defined in the program.

Overloaded functions can be called only if there is an exact parameter match or a match that does not require the construction of an object.

This error is identical to CAN0047.


Expression Evaluator Error CXX0048

calling sequence not supported

A function specified in the expression uses a calling sequence not supported by the C expression evaluator. You cannot call this function in a Watch window expression.

This error is identical to CAN0048.


Expression Evaluator Error CXX0049

obsolete OMF - please relink program

The program used an old OMF (Object Module Format).

The program must be linked with LINK version 5.30 or later, and packed with CVPACK version 4.0 or later.

This error is identical to CAN0049.


Expression Evaluator Error CXX0050

left side of :: must be class/struct/union

The symbol on the left side of the scope-resolution operator (::) was not a class, structure, or union.

This error is identical to CAN0050.


Expression Evaluator Error CXX0051

more than one overloaded symbol specified in breakpoint

The expression evaluator could not determine which of more than one overloaded symbol to use as a breakpoint.

This error is identical to CAN0051.


Expression Evaluator Error CXX0052

member function not present

A member function was specified as a breakpoint but could not be found. This error can be caused by setting a breakpoint at a function that has been inlined.

Recompile the file with inlining forced off (/Ob0) to set a breakpoint in this function.

An expression called a function that was not defined.

This error is identical to CAN0052.


Expression Evaluator Error CXX0053

nonfunction symbol match while binding breakpoints

A symbol used as a breakpoint was not a function. This error can be caused by specifying a data member as a breakpoint.

This error is identical to CAN0053.


Expression Evaluator Error CXX0054

register in breakpoint expression illegal

A register cannot be used in a breakpoint expression.

This error is identical to CAN0054.


Expression Evaluator Error CXX0055

ambiguous symbol in context operator

A symbol in the context operator ({}) referred to more than one symbol in the program.

The scope resolution operator (::) may be able to resolve the ambiguity.

This error is identical to CAN0055.


Expression Evaluator Error CXX0056

error in line number

An invalid line number was specified.

This error is identical to CAN0056.


Expression Evaluator Error CXX0057

no code at line number

No code was generated for the specified line number. It cannot be used as a breakpoint.

This error is identical to CAN0057.


Expression Evaluator Error CXX0058

overloaded operator not found

A class type was specified as the left operand in an expression, but an overloaded operator was not defined for the class.

This error is identical to CAN0058.


Expression Evaluator Error CXX0059

left operand is class not a function name

The left operand of a function call was a class name and could not be resolved to a function call. This error can be caused by omitting the name of a member function in an expression.

This error is identical to CAN0059.


Expression Evaluator Error CXX0060

register is not available

An expression specified a register that cannot be used.

This error can be caused by trying to access a register that does not exist on the machine running.

This error is identical to CAN0060.


Expression Evaluator Error CXX0061

function nesting depth exceeded

The expression contains a function nesting depth greater than the limit.

Modify the expression to reduce the nesting depth.

This error is identical to CAN0061.


Expression Evaluator Error CXX0062

constructor calls not supported

An expression made a call to a constructor.

Expressions cannot make explicit calls to constructors or make conversions that require a call to a constructor.

This error is identical to CAN0062.


Expression Evaluator Error CXX0063

overloaded operator -> not supported

The expression used an overloaded class member access operator (->).

This error is identical to CAN0063.


Expression Evaluator Error CXX0064

can't set breakpoint on bound virtual member function

A breakpoint was set on a virtual member function through a pointer to an object, such as:

pClass->vfunc( int );

A breakpoint can be set on a virtual function by entering the class, such as:

Class::vfunc( int );

This error is identical to CAN0064.


Expression Evaluator Error CXX0065

variable needs stack frame

An expression contained a variable that exists within the current scope but hasn't been created yet.

This error can occur when you have stepped into the prolog of a function but not yet set up the stack frame for the function, or if you have stepped into the exit code for the function.

Step through the prolog code until the stack frame has been set up before evaluating the expression.

This error is identical to CAN0065.


Expression Evaluator Error CXX0066

static member not present

A static member of a class could not be found or was not defined. This error can result from a static class member that is declared but not defined, or is only defined and referenced in modules that do not contain debug information.

This error is identical to CAN0066.


Expression Evaluator Error CXX0067

function evaluation not supported

The expression contained a function call. Some expression evaluators do not support function calls.

This error is identical to CAN0067.


Expression Evaluator Error CXX0069

variable needs stack frame

The expression evaluator cannot evaluate the variable because it does not occur in a stack frame. This may be caused by variables declared as part of an inline function.


Expression Evaluator Error CXX0072

Error: type information missing or unknown

The .PCH file did not get linked in, or the code has a reference to a type that is in a module not compiled with /Zi.

This error is identical to CAN0067.


CVPACK Errors CK1001 through CK4010

The following topics cover error CK1001 through warning CK4010.


CVPACK Fatal Error CK1001

out of memory

CVPACK ran out of memory.

One of the following may be a solution:

  • Free some space on disk.

  • Increase the size of the Windows NT paging file or the Windows swap file.

  • Recompile one or more of the object files without debugging information. If the file was compiled using /Zi or /Z7, either use /Zd or do not use a debugging option.


CVPACK Fatal Error CK1002

out of memory

CVPACK ran out of memory.

One of the following may be a solution:

  • Free some space on disk.

  • Increase the size of the Windows NT paging file or the Windows swap file.

  • Recompile one or more of the object files without debugging information. If the file was compiled using /Zi or /Z7, either use /Zd or do not use a debugging option.


CVPACK Fatal Error CK1003

cannot open file : filename

CVPACK could not open the given file.

One of the following may be a cause:

  • The file does not exist. Check the spelling of the filename and path.

  • The file was opened or deleted by another process.

  • There was not enough space on disk.


CVPACK Fatal Error CK1004

filename is read-only

The given file is a read-only file, or the path is on a read-only drive.


CVPACK Fatal Error CK1005

invalid executable file

CVPACK could not process the executable file.

One of the following may be a cause:

  • The debugging information in the executable file is corrupt.

  • The executable file is a zero-length file.


CVPACK Fatal Error CK1006

invalid module module

The module does not have a valid format or is corrupt. Recompile and relink.


CVPACK Fatal Error CK1007

invalid table table in module module

The given table in the given object file is not valid, or the module is corrupt. Recompile and relink. If the error recurs, try using different options.


CVPACK Fatal Error CK1008

cannot write output file

The disk is probably full.

This error leaves a corrupt file on disk.


CVPACK Fatal Error CK1011

type information corrupt, recompile module modulename

The given object file contains corrupted information.

Recompile. If compiling with /Zi, try /Z7. If compiling with /Z7, try /Zi.


CVPACK Fatal Error CK1012

no debugging information

The executable file does not contain debugging information.

Do one of the following:

  • To put at least minimal debugging information into the executable file, link using the /DEBUG option.

  • To include full debugging information in an object file, compile or assemble using the /Zi or /Z7 option.

  • To include minimal information and line numbers in an object file, compile or assemble using the /Zd option.


CVPACK Fatal Error CK1013

incompatible version of debugging information

One of the following has occurred:

  • The executable file was linked using an obsolete or unsupported linker.

  • The executable file was already packed using a previous version of CVPACK.

  • The executable file is corrupt. Recompile and relink.


CVPACK Fatal Error CK1017

cannot find precompiled types file; relink with filename

The program used a precompiled header, but the program was linked without filename. This file is the object file that was created when the header was precompiled. If the program uses a library that was created using precompiled headers, then filename was not linked from the library.

One of the following may be a solution:

  • Extract the object from the library and link it to the program explicitly.

  • Force LINK to include the object in the program by specifying the /INCLUDE option with a symbol from the object.

  • Change the source code so that code or data in filename is referenced either from an object file that uses the library or from another module that is being linked from the library.


CVPACK Fatal Error CK1018

userfile cannot use precompiled types file pctfile : type counts do not match

The userfile uses the precompiled types file pctfile, but pctfile does not contain the correct number of types for userfile.

Recompile userfile and relink. If a makefile is used, check the makefile dependencies.


CVPACK Fatal Error CK1021

userfile cannot use precompiled types file pctfile : signatures do not match

The userfile uses the precompiled types file pctfile, but the internal signature in pctfile does not match the internal signature in userfile. Probably pctfile was rebuilt but userfile was not rebuilt.

Recompile userfile and relink. If a makefile is used, check the makefile dependencies.


CVPACK Fatal Error CK1022

cannot open program database pdbfile

CVPACK could not open the given program database (.PDB file).

One of the following may be a cause:

  • The .PDB file does not exist. Check the spelling of the filename and path.

  • The .PDB file was opened or deleted by another process.

CVPACK and LINK look for .PDB files in the following locations in this order:

  1. Where the .EXE or .DLL resides (the absolute path written in the .OBJ file).

  2. Where the .OBJ or .DLL is opened from.

You cannot specify a .PDB file's name or location on the command line.


CVPACK Fatal Error CK1023

modulename cannot use program database pdbfile : module newer than database

The .OBJ file modulename uses the .PDB file pdbfile, but pdbfile is older than modulename.

Recompile and relink. If a makefile is used, check the makefile dependencies.


CVPACK Fatal Error CK1024

modulename cannot use program database pdbfile : signatures do not match

The .OBJ file modulename uses the .PDB file pdbfile, but the internal signature in pdbfile does not match the internal signature in modulename.

Delete modulename, recompile, and relink. If a makefile is used, check the makefile dependencies.


CVPACK Fatal Error CK1025

incorrect COFF symbol table

CVPACK was unable to interpret the COFF symbols emitted by the compiler. Recompile and relink.


CVPACK Fatal Error CK1027

you have accessed an incorrect version of MSPDB60.DLL, recheck your installation


CVPACK Fatal Error CK1028

file compiled /Yc /Yu /Z7; cannot create debug info, recompile all with /Zi

You created two PCH files, one based on the other using the /Z7 compiler option. Only one precompiled type object can be referenced. The only way to use PCH files based on other PCH files is to use the /Zi compiler option to put all types in the .PDB file.


CVPACK Warning CK4001

file already packed

CVPACK took no action because the executable file has already been processed by this version of CVPACK.


CVPACK Warning CK4003

error in lexical scopes for module module; symbols deleted

The scoping of symbols in the given object module was corrupted. CVPACK deleted the symbols in the module.

This is probably a compiler error. Recompile and relink the object file.


CVPACK Warning CK4004

unrecognized symbols discarded; recompile module modulename

The compiler generated an invalid symbol record in the modulename object file. CVPACK discarded the record.

The debugger can run the resulting executable file. However, the symbol will be accessible only by the decorated name known to the linker, and display of the symbol will be limited. To see decorated names of identifiers, use DUMPBIN /UNDECORATE.


CVPACK Warning CK4005

unrecognized type converted to NULL; recompile module modulename

The compiler generated an invalid type record in the modulename object file. CVPACK discarded the record.

The debugger can run the resulting executable file, but display of objects that reference the invalid type will be limited.


CVPACK Warning CK4006

type length limit exceeded; converted to NULL

A struct, enum, union, or class was too large for CVPACK to process. You can use the executable file with the debugger, but you cannot reference the object or type while debugging.


CVPACK Warning CK4007

unrecognized option /option; option ignored

The given option is not a valid CVPACK option. CVPACK ignored the specification and attempted to run using the rest of the command line.


CVPACK Warning CK4008

source line limit exceeded in module filename; source line info discarded

CVPACK could not translate the debugging information in the given filename module because filename was too large. CVPACK discarded the debugging information for this module.

Break up the module into smaller files.


CVPACK Warning CK4009

exceeded 64K types at module; discarding subsequent types

The debugging information exceeded a CVPACK limit.

One of the following may be a solution:

  • Compile some object files without debugging information.

  • Avoid including unneeded header files.

The checksum can be calculated only when running on Windows NT.


CVPACK Warning CK4010

cannot update checksum

The checksum can be calculated only when running on Windows NT.


Command-line Errors D2000 through D4028

The following topics cover error D2000 through warning D4028.


Command-line Error D2000

unknown error; consult documentation for technical support options

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Command-line Error D2016

'option1' and 'option2' command-line options are incompatible

The given command-line options cannot be specified together.

For example, the following command line generates this error:

cl /Gw /NDxx program.c

In this example, the /Gw and /NDxx options are incompatible because each has a different special-entry sequence.

Check the CL or FL environment variable for option specifications.


Command-line Error D2018

cannot create linker response file

The compiler could not create a response file for passing arguments to the linker.

This error can occur when an existing read-only file has the same name as the filename the compiler gives to the response file.


Command-line Error D2021

invalid numeric argument 'number'

A number greater than 65,534 was specified as a numeric argument.


Command-line Error D2022

cannot open 'messagefile'

The given file was not in the current directory or in a directory specified in the PATH environment variable. The message file contains a brief summary of compiler command-line syntax and options.

Move this file to the current directory or a directory in the current path. If this file cannot be found, run the SETUP program to copy it from the distribution disks.


Command-line Error D2027

cannot execute 'component'

The compiler could not run the given compiler component or linker.

One of the following may have occurred:

  • Not enough memory was available to load the component. If this error occurred when NMAKE invoked the compiler, run the compiler outside of the makefile.

  • The current operating system could not run the component. Make sure the path points to the executable files appropriate to your operating system.

  • The component was corrupted. Recopy the component from the distribution disks, using the SETUP program.

  • An option was specified incorrectly. For example, the following CL command generates this error:
    cl /B1 file1.c


Command-line Error D2028

too many open files; cannot redirect 'filename'

Redirection of one of the standard stream files was not possible because too many files were already open and a duplicate handle could not be created.


Command-line Error D2030

INTERNAL COMPILER ERROR in 'component'

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Command-line Error D2034

error reading 'filename'

The specified file was opened but could not be read.

This error may be caused by a hardware failure.


Command-line Error D2035

response files nested too deeply

Move the directives in a nested response file into the calling response file.

This error can be caused by a recursively nested response file.


Command-line Error D2036

'/option' not allowed with multiple source files

The following compiler options cannot be used with multiple source files:

  • Name assembly file listing (/Fa)

  • Rename object file (/Fo)

  • Create source browser information without local variables (/Fr)

  • Create source browser information that includes local variables (/FR)


Command-line Warning D4000

unknown warning; consult documentation for technical support options

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Command-line Warning D4002

ignoring unknown option 'option'

The compiler did not recognize the given command-line option; the option was ignored.

Check the CL or FL environment variable for option specifications.


Command-line Warning D4007

'option1' requires 'option2'; option ignored

An option was specified without a required related option. The compiler ignored option1.

For example, the following command line generates this warning:

cl /C program.c

In this example, the /C option was given instead of /c. The /C option must be used with /E, /P, or /EP.

Check the CL or FL environment variable for option specifications.


Command-line Warning D4014

invalid value 'number1' for 'option'; assuming 'number2'

The given option was specified with an invalid numeric argument. The compiler assumed the value number2.

For example, the following command generates this warning:

cl /Zp3 program.c

In this example, 3 is an invalid value. Valid arguments for the /Zp option are 1, 2, and 4.


Command-line Warning D4015

invalid assembly listing configuration 'option'

The List Assembly option (/FA) can specify combined source and assembly code (/FAs) or combined source and machine code (/FAc). Other specifiers for the List Assembly option are invalid.


Command-line Warning D4020

'option' : missing argument; option ignored

A command-line option required an argument, but nothing was specified. CL ignored the option.


Command-line Warning D4021

no action performed

A contradictory set of filenames and switches caused the compiler to perform no operation.

This warning can be generated by giving the /c Compile-Only command-line option and specifying no .C, .CPP, or .CXX files to compile.


Command-line Warning D4024

unrecognized source file type 'filename', object file assumed

The extension of the specified file was not recognized. The file was assumed to be an object file and was passed to the linker.

The following extensions are recognized:

  • .C (C source file)

  • .CXX (C++ source file)

  • .CPP (C++ source file)

  • .OBJ (Object file)

  • .LIB (Library file)

  • .DEF (Module definition file)

  • .EXP (Linker exports file, created by LINK /LIB)


Command-line Warning D4025

overriding 'option1' with 'option2'

The option1 option was specified but was then overridden by option2. The option2 option was used.

If two options specify contradictory or incompatible directives, the directive specified or implied in the option farthest to the right on the command line is used.


Command-line Warning D4026

options apply to entire command line

An option was specified on a command after a filename was specified. The option was applied to the file that preceded it.

For example, in the command

CL verdi.c /G5 puccini.c

the file VERDI.C will be compiled using the /G5 option, not the /G4 default.

This behavior is different from that of some previous versions, which applied only the options specified before the filename, resulting in VERDI.C being compiled using /G4 and PUCCINI.C being compiled using /G5.


Command-line error D4027

source file '<filename>' ignored

The CL.EXE did not take the source file <filename> as an input file.

This happens, for example, if you inadvertently include a space between the /Fo option and an output filename on a command line with the /c option. In the following command line, CL.EXE would take output.obj as the name of an input file because there is a space between /Fo and output.obj:

cl /c /Fo output.obj input.c

In this case, the fix is to remove the space, thus:

cl /c /Fooutput.obj input.c


Command-line error D4028

minimal rebuild failure, reverting to normal build

An error was detected in the project .IDB file, indicating a corrupt .IDB. Delete the .IDB and rebuild.

For more information on minimal rebuilds and the .IDB file, see the /Gm compiler option.


Linker Tools Errors and Warnings

The linker tools errors and warnings (LNKnnnn) are generated by LINK, LIB, DUMPBIN, and EDITBIN.


Linker Tools Error LNK1000

unknown error; consult documentation for technical support options

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Linker Tools Error LNK1101

incorrect MSPDB60.DLL version; recheck installation of this product

The version of MSPDB60.DLL available on your system does not match the version required by this tool.


Linker Tools Error LNK1102

out of memory

There was not enough memory for the tool to run. Probably the paging file exceeded available disk space.

If a shortage of disk space is not the cause, note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Linker Tools Error LNK1103

debugging information corrupt; recompile module

Probably the compilation was terminated before a valid object file was created.

Recompile the given object file. If recompiling does not correct the problem, note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.

See Corrupt Object File for more information.


Linker Tools Error LNK1104

cannot open file "filename"

The tool could not open the given file.

Tips

One of the following may be a cause:

  • There was not enough disk space.

  • The file does not exist.

  • The filename or its path was incorrectly specified.

  • The specified drive is invalid.

  • The file does not have the appropriate permissions.

  • The path for filename expands to more than 260 characters.

  • If the given file is named LNKn, which is a filename generated by the linker for a temporary file, then the directory specified in the TMP environment variable may not exist, or more than one directory is specified for the TMP environment variable. (Only one directory path should be specified for the TMP environment variable.)

  • If the error occurs on the executable filename, an earlier version of the executable may still be running. You will need to terminate the executable before linking it. In Windows NT or Windows 95 you can use the utility PVIEW to look for and kill instances of the application. PVIEW.EXE is shipped with Visual C++.

  • If the error message occurs for a library name, and you recently ported the .MAK file from a previous Microsoft Visual C++ development system, the library may no longer be valid. Ensure that the library still exists in this circumstance.


Linker Tools Error LNK1105

cannot close file "filename"

The tool could not close the given file. Possibly there was insufficient disk space available.


Linker Tools Error LNK1106

invalid file or disk full: cannot seek to location

The tool could not read or write to location in a memory-mapped file.

Tips

  • Your disk may be too full to complete the link. Free up some space and try the link again.

  • The error may be a result of trying to link over a network. Some networks do not fully support the memory-mapped files used by the linker. Try linking on your local disk to see if that fixes the problem.

  • There may be a bad block on your disk. Although the operating system and disk hardware should have detected such an error, you may want to run a disk checking program.


Linker Tools Error LNK1107

invalid or corrupt file: cannot read at location

The tool could not read the file. Recreate the file.


Linker Tools Error LNK1108

cannot write file at location

The tool could not write to the file. One of the following may be a cause:

  • There was not enough disk space to create the file.

  • The drive being written to was not available, possibly due to a network problem.


Linker Tools Error LNK1109

cannot remove file "filename"

LIB could not delete the given file.

Before LIB writes the new version of a library, it removes the existing library file.

One of the following may be a cause:

  • The given file does not have the appropriate permissions.

  • The drive containing the file was not available, possibly due to a network problem.


Linker Tools Error LNK1110

cannot rename file "filename"

LIB could not rename the given file.

When LIB builds a new version of a library, it creates a temporary file, then renames the file.

One of the following may be a cause:

  • The given file does not have the appropriate permissions.

  • The drive containing the file was not available, possibly due to a network problem.


Linker Tools Error LNK1111

invalid /BASE argument "argument"

The /BASE option was incorrectly specified. Either no argument was specified or argument is not a number.


Linker Tools Error LNK1112

module machine type "type1" conflicts with target machine type "type2"

The object files specified as input were compiled for different machine types.


Linker Tools Error LNK1113

invalid machine type

The machine type specified in the object header is not valid. Probably the file is corrupt. Rebuild the object.

See Corrupt Object File for more information.


Linker Tools Error LNK1115

/MACHINE option required

LINK or LIB cannot determine the machine type for objects that are provided entirely from libraries. Either specify the /MACHINE option with the appropriate machine type or specify at least one object file in the input.


Linker Tools Error LNK1117

syntax error in option "option"

The given option was not correctly specified.


Linker Tools Error LNK1118

syntax error in keyword statement

The given module-definition statement was not correctly specified.


Linker Tools Error LNK1119

invalid ordinal number "argument"

The argument following the at sign (@) in an ordinal specification was not a valid number.

An ordinal number is an optional argument in either an /EXPORT option in a LINK or LIB command or an EXPORTS statement in a module-definition file. It is an index into the exports table. The number must be an integer in the range 1–65535.


Linker Tools Error LNK1120

number unresolved externals

Error LNK1120 gives you a count (number) of unresolved externals for this link. The conditions that cause unresolved externals are described with error LNK2001, which precedes this error message (once for each unresolved external).


Linker Tools Error LNK1121

duplicate ordinal number "number"

The given ordinal number was specified more than once in either an /EXPORT option in a LINK or LIB command or an EXPORTS statement in a module-definition file. Ordinal numbers must be unique integers in the range 1–65535.


Linker Tools Error LNK1123

failure during conversion to COFF: file invalid or corrupt

The object or resource could not be converted to COFF.

This tool requires the format of all input files to be COFF. If an input file is not COFF, the tool runs a conversion tool, either CVTOMF (to convert 32-bit OMF objects) or CVTRES (to convert resource files).

One of the following may be a cause:

  • The file is corrupt.

  • The file is not a valid file type. An example of an invalid type is a 16-bit OMF object.

This error is preceded by errors or warnings from the conversion tool.


Linker Tools Error LNK1127

library is corrupt

The library file is corrupt. Rebuild the library.


Linker Tools Error LNK1129

cannot find resolution for weak extern symbol

The given weak external symbol does not have a default resolution. Probably the symbol table is corrupt. Rebuild the object file.

See Corrupt Object File for more information.


Linker Tools Error LNK1130

Linker miscalc (base relocations off by number)

There was not enough space in the image to write base relocations.


Linker Tools Error LNK1131

no library file specified

The LIB /EXTRACT command required a library as input, but a library filename was not specified.


Linker Tools Error LNK1132

invalid format for MS-DOS stub file "filename"

The filename specified with the /STUB option was not a valid real-mode MS-DOS executable (.EXE) file.


Linker Tools Error LNK1136

invalid or corrupt file

The input file either has a corrupt header or is zero size or abnormally small.

See Corrupt Object File for more information.


Linker Tools Error LNK1137

invalid argument specified with /SECTION

Either the name or the attributes argument to the /SECTION option is specified incorrectly.


Linker Tools Error LNK1140

too many modules for program database; relink with /PDB:NONE

The project contains more than 4096 modules. One of the following is a solution:

  • Relink using /PDB:NONE.

  • Compile some modules without debugging information.

  • Reduce the number of modules.


Linker Tools Error LNK1141

failure during build of exports file

LINK could not build the exports (.EXP) file.

Causes of this error include system problems such as insufficient memory and syntax errors in options or module-definition statements.

This error is preceded by another error that gives additional information.


Linker Tools Error LNK1143

invalid or corrupt file: no symbol for COMDAT section number

The object file is corrupt. Rebuild the file.

See Corrupt Object File for more information.


Linker Tools Error LNK1144

error with LINK_REPRO var; cannot open "filename"

The linker could not create filename.

One of the following may be a cause:

  • Check that you've set your LINK_REPRO environment variable to an existing directory and not the current directory.

  • Make sure there are no read-only files in the directory.

  • Make sure none of the files in the LINK_REPRO directory are open by another process, because the linker needs to write to them.


Linker Tools Error LNK1145

/MERGE created circular link for section "section"

You attempted to merge a section into itself. Check the /MERGE options.


Linker Tools Error LNK1146

no argument specified with option "option"

The given option requires an argument.


Linker Tools Error LNK1147

invalid number specified with option "option"

The argument to the given option was specified incorrectly.


Linker Tools Error LNK1148

failure during conversion to COFF: cannot copy temp file filename

EDITBIN could not convert the input file to COFF.

When EDITBIN converts a file, it creates a temporary file, then copies the file.

One of the following may be a cause:

  • The given file does not have the appropriate permissions.

  • There was not enough disk space to create the file.

  • The drive being written to was not available, possibly due to a network problem.


Linker Tools Error LNK1149

output filename matches input filename "filename"

The output filename specified with the /OUT or /IMPLIB option was the same as an input file.


Linker Tools Error LNK1152

cannot resolve one or more undecorated symbols

This error is preceded by one warning LNK4022 for each undecorated symbol that could not be resolved and by at least two warnings LNK4006 for the duplicate symbols found for the undecorated symbol.


Linker Tools Error LNK1153

/VXD command-line option required

You attempted to build a virtual device driver without the /VXD option. Relink with the /VXD option.


Linker Tools Error LNK1154

specified import library filename matches exports file "filename"

The filename specified with LINK /IMPORT or with LIB /DEF /OUT conflicted with the filename given by LINK or LIB to the exports file, which is formed from the base name of the main output file and the extension .EXP.


Linker Tools Error LNK1155

special symbol "symbol" already defined

The given symbol is reserved for use by LINK.


Linker Tools Error LNK1156

.sbss section not supported

An object file contained an .sbss section.


Linker Tools Error LNK1157

fixup overflow; offset of target symbol "symbol" greater than +-8MB

The VXD is too large, or the sections are not arranged properly.


Linker Tools Error LNK1158

cannot run "filename"

The given executable file called by LINK is not in the directory that contains LINK and is not in a directory specified in the PATH environment variable.


Linker Tools Error LNK1159

no output file specified

No name was specified for the main output file (executable file or DLL).

LINK derives the default name of the output file from the base name of the first object file. If no object files are specified, and if the /OUT option is not used, this error occurs.


Linker Tools Error LNK1160

library with zero objects not allowed

An attempt was made to remove an object from a library that contained only that object. The object was not removed.


Linker Tools Error LNK1161

invalid export specification

Either the /EXPORT option or the EXPORTS module-definition statement incorrectly specified an export. A possible cause is a typing error.


Linker Tools Error LNK1162

expected aux symbol for comdat section number

The linker expected to find an auxiliary symbol table for the indicated COMDAT but could not. The object file is probably corrupt.

See Corrupt Object File for more information.


Linker Tools Error LNK1163

invalid selection for comdat section number

The byte in the object file indicating the type of COMDAT section is invalid. The object file is probably corrupt.

See Corrupt Object File for more information.


Linker Tools Error LNK1164

section section alignment (number) greater than /ALIGN value

The alignment size for the given section in the object file exceeds the value specified with the /ALIGN option. The /ALIGN value must be a power of 2 and must equal or exceed the section alignment given in the object file.

Either recompile with a smaller section alignment or increase the /ALIGN value.


Linker Tools Error LNK1165

link failed because of fixup errors

The build failed due to fixup errors.

The /FORCE or /FORCE:UNRESOLVED option overrides this error.


Linker Tools Error LNK1166

cannot adjust code at offset=offset, va=value

LINK was unable to pad the code as required.

Certain instructions are not allowed to cross page boundaries on some processors. LINK attempts to add pads to correct this situation. In this case, LINK could not work around the problem.


Linker Tools Error LNK1167

file contains relocs but header has no machine type

A converted COFF object did not have a machine type specified in its header.

One cause of this error is omitting a machine type when converting a .RES file in a separate step before linking.


Linker Tools Error LNK1168

cannot open filename for writing

The given file does not have write permission.


Linker Tools Error LNK1169

one or more multiply defined symbols found

The build failed due to multiple definitions of one or more symbols. This error is preceded by error LNK2005.

The /FORCE or /FORCE:MULTIPLE option overrides this error.


Linker Tools Error LNK1170

line in command file contains limit or more characters

The length of a line in a command file must be less than the given limit.


Linker Tools Error LNK1171

unable to load filename

The given DLL was unavailable.

The possible locations for the DLL are the current directory, the system directory, the Windows directory, and the directories specified in the PATH environment variable.


Linker Tools Error LNK1172

more than one object with the name "object" found; rename object(s) or relink /PDB:NONE

A library contained two or more objects with the same name. Do one of the following:

  • Rename the objects using unique names and rebuild the library.

  • Link using the /PDB:NONE option.


Linker Tools Error LNK1173

unable to find entrypoint function in filename

The given function does not exist in the given DLL.


Linker Tools Error LNK1174

unable to /REBASE filename; not a valid Win32 image

The format of the given file was invalid.


Linker Tools Error LNK1175

failed to /REBASE filename

The rebase operation failed on the given file.


Linker Tools Error LNK1177

TOC size limit exceeded

The linker was unable to create a TOC (Table of Contents) in your image file. The limit is 2048 entries in the TOC.


Linker Tools Error LNK1178

missing MODEND record; file is invalid or corrupt

The linker tool tried to convert an OMF object module to COFF format but could not find an expected MODEND (module end) record in the OMF object. The OMF object module is corrupt and needs to be recreated or recopied.

See Corrupt Object File for more information.


Linker Tools Error LNK1179

invalid or corrupt file: duplicate comdat comdat

An object module contained two or more COMDATs with the same name.

One possible cause is if you use the /H option with /Gy. The /H option limits the length of external names, and the /Gy option packages functions in COMDATs.

For example, if you compile the following with /Gy and /H8, you will get error LNK1179 since the object module will contain two COMDATs of the same name (function1 and function2 are unique at nine characters):

void function1(void);
void function2(void);

void main(void) {
    function1();
    function2();
}

void function1(void) {}
void function2(void) {}


Linker Tools Error LNK1180

insufficient disk space to complete link

The linker tool was unable to complete a file operation since the operating system reported that the disk is full.

Free up space on your local and network drives (if you are writing files there).


Linker Tools Error LNK1181

cannot open input file "filename"

The linker tool could not find "filename" because it does not exist or the path was not found.


Linker Tools Error LNK1182

cannot have more than 64K exports

You have reached the linker's limit of 65,536 exports.


Linker Tools Error LNK1183

invalid or corrupt file: extended relocation count number less than 65535

The COFF object file is corrupt since it contains an extended relocation count that is less than 0xFFFF.

See Corrupt Object File for more information.


Linker Tools Error LNK1184

invalid section name "section" specified in option or directive "option"

You gave the linker an invalid section name in option. Invalid section names contain "$" or blanks.


Linker Tools Error LNK1185

invalid section name "section" specified

You gave the linker an invalid section name in a .DEF file. Invalid section names contain "$" or blanks.


Linker Tools Error LNK1186

invalid or corrupt COFF object; reloc to undefined static symbol "symbol"

Your COFF object module is corrupt since it contains a relocation entry for an undefined static symbol.

See Corrupt Object File for more information.


Linker Tools Error LNK1187

Corrupt object - unmatched name relocation; ignored

Your object file contains bad relocation information. Recopy or recreate the object file.

See Corrupt Object File for more information.


Linker Tools Error LNK1188

BADFIXUPSECTION:: invalid fixup target "symbol"; possible zero length section

This message is issued only for VxD links when the target of a relocation does not have a section. With LINK386 (an older version), an OMF GROUP record (generated by a MASM GROUP directive) may have been used to combine the zero length section with another non-zero length section. COFF format does not support the GROUP directive and zero-length sections. When LINK automatically converts this type of OMF objects to COFF, this error may occur.


Linker Tools Error LNK1189

LIBTOOMANYMEMBERS:: library limit of number objects exceeded

The limit of 65535 objects or members in a library has been exceeded.


Linker Tools Error LNK1190

invalid fixup found, type type

The object file has become corrupted. Recompile.


Linker Tools Error LNK1194

cannot delay-load dll name due to import of data symbol symbol name; relink without /DELAYLOAD:dll name

You cannot delay load a DLL if data is imported from it.


Linker Tools Error LNK1195

target machine "machine" requires "option"

Add the required option.


Linker Tools Error LNK1196

invalid or corrupt import object: unknown version

The import library has become corrupted. Rebuild the library.


Linker Tools Error LNK1197

invalid or corrupt import object: unknown type

The import library has become corrupted. Rebuild the library.


Linker Tools Error LNK1198

invalid or corrupt import object: unknown name type

The import library has become corrupted. Rebuild the library.


Linker Tools Error LNK1199

invalid or corrupt import object: non-zero reserved fields

The import library has become corrupted. Rebuild the library.


Linker Tools Error LNK1200

error reading program database "filename"

The given program database (PDB) could not be read, probably because it is corrupted.

If filename is the PDB for an object file, recompile the object file; use CL's /Zi option.

If filename is the PDB for the main output file and this error occurred during an incremental link, delete the PDB and relink.


Linker Tools Error LNK1201

error writing to program database "filename"; check for insufficient disk space

LINK could not write to the program database (PDB) for the output file. One of the following may be a cause:

  • The file is corrupted. Delete filename and relink.

  • There was not enough disk space to write to the file.

  • The drive being written to was not available, possibly due to a network problem.


Linker Tools Error LNK1202

"filename" missing debugging information for referencing module

The given program database (PDB) for an object file was invalid. Recompile the object file; use CL's /Zi option.


Linker Tools Error LNK1203

"filename" missing current debugging information for referencing module

The given program database (PDB) for an object file was invalid. Recompile the object file; use CL's /Zi option.


Linker Tools Error LNK1204

"filename" compiled /Yc /Yu /Z7; cannot create PDB; recompile with /Zi

Multilayered program databases (PDBs) are not supported in combination with old-style debugging information. Recompile using CL’s /Zi option.


Linker Tools Error LNK1206

cannot overwrite Visual C++ 1.0 PDB "filename"; delete and rebuild

This version of LINK cannot write to an existing program database (PDB) created using Visual C++ version 1.0. Delete filename and rebuild.


Linker Tools Error LNK1207

incompatible PDB format in "filename"; delete and rebuild

This version of LINK cannot write to the existing program database (PDB). Delete filename and rebuild.


Linker Tools Error LNK1209

program database "filename" differs from previous link; relink or rebuild

The given program database (PDB) is invalid and possibly corrupt. Relink. If filename is also the PDB for an object file, recompile to recreate the PDB.


Linker Tools Error LNK1210

insufficient memory for incremental link; relink with /INCREMENTAL:NO

There was not enough memory available for LINK to create the incremental status (.ILK) file.


Linker Tools Error LNK1211

precompiled type information not found; "filename" not linked or overwritten

The given object file, compiled with /Yc, either was not specified in the LINK command or was overwritten.


Linker Tools Error LNK1212

error opening program database; file is in use

The PDB is already in use by another application.


Linker Tools Error LNK1213

unexpected import object encountered

The import library has become corrupted. Rebuild the library.


Linker Tools Error LNK1221

a subsystem can’t be inferred and must be defined

The linker does not have enough information to infer which subsystem you will target your application.

To fix this error, use the /SUBSYSTEM option.


Linker Tools Error LNK1561

entry point must be defined

The symbol specified by the /ENTRY option is not defined.


Linker Tools Error LNK1581

corrupted object or old compiler (bad Pcode entry point)

Your object file contained a bad entry point. The object file is probably corrupt.

See Corrupt Object File for more information.


Linker Tools Error LNK2001

unresolved external symbol "symbol"

Code will generate this error message if it references something (like a function, variable, or label) that the linker can’t find in all the libraries and object files it searches. In general, there are two reasons this error occurs: what the code asks for doesn’t exist (the symbol is spelled incorrectly or uses the wrong case, for example), or the code asks for the wrong thing (you are using mixed versions of the libraries?some from one version of the product, others from another version).

Numerous kinds of coding and build errors can cause LNK2001. Several specific causes are listed below, and some have links to more detailed explanations.

Coding Problems

  • Mismatched case in your code or module-definition (.DEF) file can cause LNK2001. For example, if you named a variable “var1” in one C++ source file and tried to access it as “VAR1” in another, you would receive this error. The solution is to exactly match the case of the symbol in all references.

  • A project that uses function inlining yet defines the functions in a .CPP file rather than in the header file can cause LNK2001.

  • If you are using C++, make sure to use extern “C” when calling a C function from a C++ program. By using extern “C” you force the use of the C naming convention. Be aware of compiler switches like /Tp or /Tc that force a file to be compiled as a C (/Tc) or C++ (/Tp) file no matter what the filename extension, or you may get different function names than you expect.

  • Attempting to reference functions or data that don't have external linkage causes LNK2001. In C++, inline functions and const data have internal linkage unless explicitly specified as extern.

  • A missing function body or variable will cause LNK2001. Having just a function prototype or extern declaration will allow the compiler to continue without error, but the linker will not be able to resolve your call to an address or reference to a variable because there is no function code or variable space reserved.

  • Name decoration incorporates the parameters of a function into the final decorated function name. Calling a function with parameter types that do not match those in the function declaration may cause LNK2001.

  • Incorrectly included prototypes will cause the compiler to expect a function body that is not provided. If you have both a class and non-class implementation of a function F, beware of C++ scope-resolution rules.

  • When using C++, make sure that you include the implementation of a specific function for a class and not just a prototype in the class definition.

  • Attempting to call a pure virtual function from the constructor or destructor of an abstract base class will cause LNK2001 since by definition a pure virtual function has no base class implementation.

  • Only global functions and variables are public.

    Functions declared with the static modifier by definition have file scope. Static variables have the same limitation. Trying to access any static variables from outside of the file in which they are declared can result in a compile error or LNK2001.

    A variable declared within a function (a local variable) can only be used within the scope of that function.

    C++ global constants have static linkage. This is different than C. If you try to use a global constant in C++ in multiple files you get error LNK2001. One alternative is to include the const initializations in a header file and include that header in your .CPP files when necessary, just as if it was a function prototype. Another alternative is to make the variable non-constant and use a constant reference when assessing it.

Compiling and Linking Problems

  • The names of the Microsoft run-time and MFC libraries needed at link time are included in the object file module by the Microsoft compiler. If you use the /NOD (/NODEFAULTLIB) option, these libraries will not be linked into the project unless you have explicitly included them. Using /NOD will cause error LNK2001 in this case.

  • If you are using Unicode and MFC, you will get an unresolved external on _WinMain@16 if you don’t create an entrypoint to wWinMainCRTStartup. Use the /ENTRY option or type this value in the Project Settings dialog box. (To find this option in the development environment, click Settings on the Project menu, then click the Link tab, and click Output in the Category box.) See Unicode Programming Summary.

    See the following Knowledge Base articles located in the Online Information System for more information. An easy way to reach an article is to copy a "Q" number above, open the Search dialog box from the Help menu and select the Query tab, then paste the number into the first text box and press ENTER.
    • Q125750 "PRB: Error LNK2001: '_WinMain@16': Unresolved External Symbol"

    • Q131204 "PRB: Wrong Project Selection Causes LNK2001 on _WinMain@16"

    • Q100639 "Unicode Support in the Microsoft Foundation Class Library"
  • Linking code compiled with /MT with the library LIBC.LIB causes LNK2001 on _beginthread, _beginthreadex, _endthread, and _endthreadex.

  • When compiling with /MD, a reference to "func" in your source becomes a reference "__imp__func" in the object since all the run-time is now held within a DLL. If you try to link with the static libraries LIBC.LIB or LIBCMT.LIB, you will get LNK2001 on __imp__func. If you try to link with MSVCxx.LIB when compiling without /MD you will not always get LNK2001, but you will likely have other problems.

  • Linking code compiled with an explicit or implicit /ML to the LIBCMT.LIB causes LNK2001 on _errno.

  • Linking with the release mode libraries when building a debug version of an application can cause LNK2001. Similarly, using an /Mxd option (/MLd, /MTd, or /MDd) and/or defining _DEBUG and then linking with the release libraries will give you potential unresolved externals (among other problems). Linking a release mode build with the debug libraries will also cause similar problems.

  • Mixing versions of Microsoft libraries and compiler products can be problematic. A new compiler version's libraries may contain new symbols that cannot be found in the libraries included with previous versions. Use DUMPBIN to find out if a symbol is in a 32-bit object file or library.

  • There is currently no standard for C++ naming between compiler vendors or even between different versions of a compiler. Therefore linking object files compiled with other compilers may not produce the same naming scheme and thus cause error LNK2001.

  • Mixing inline and non-inline compile options on different modules can cause LNK2001. If a C++ library is created with function inlining turned on (/Ob1 or /Ob2) but the corresponding header file describing the functions has inlining turned off (no inline keyword), you will get this error. To prevent this problem, have the inline functions defined with inline in the header file you are going to include in other files.

  • If you are using the #pragma inline_depth compiler directive, make sure you have a value of 2 or greater set, and make sure you are using the /Ob1 or /Ob2 compiler option.

  • Omitting the LINK option /NOENTRY when creating a resource-only DLL will cause LNK2001.

  • Using incorrect /SUBSYSTEM or /ENTRY settings can cause LNK2001. For example, if you write a character-based application (a console application) and specify /SUBSYSTEM:WINDOWS, you will get an unresolved external for WinMain. For more information on these options and entry points, see the /SUBSYSTEM and /ENTRY linker options.

Export Problems

  • When you are porting an application from 16 to 32 bits, LNK2001 can occur. The current 32-bit module-definition (.DEF) file syntax requires that __cdecl, __stdcall, and __fastcall functions be listed in the EXPORTS section without underscores (undecorated). This differs from the 16-bit syntax, where they must be listed with underscores (decorated). For more information, see the description of the EXPORTS section of module-definition files.

  • Any export listed in the .DEF file and not found will cause LNK2001. This could be because it does not exist, is spelled incorrectly, or uses decorated names (.DEF files do not take decorated names).

This error message is followed by fatal error LNK1120.

The following sections give more detailed information on some of the issues named in the above list.

  • Missing function body or variable

  • Name decoration

  • The symbol is not public

  • Automatic (function scope) variables

  • Global constants in C++

  • Function inlining problems


Missing Function Body or Variable

Having just a function prototype will allow the compiler to continue without error, but the linker will not be able to resolve your call to an address because there is no function code or variable space reserved. You will not see this error until you create an actual call to the function that the linker must resolve.

TEST.CPP

void DoSomething(void);

void main(void)
{

DoSomething( );  // This line will cause LNK2001 because
                 // the prototype in testcls.h allows the
                 // compiler to think the function exists.
                 // The linker finds that it doesn't.
}

When using C++, make sure that you include the implementation of a specific function for a class and not just a prototype in the class definition. If you are defining the class outside of the header file be sure to include the class name before the function in the Classname::memberfunction style.

class testcls {
 public:
  static void DoSomething(void);
};

void DoSomething(void)    // Should probably be testcls::DoSomething
{
}

void main(void)
{
testcls testclsObject;
testclsObject.DoSomething( );

}


Name Decoration

Normally this refers to C++ naming conventions, but it applies to a number of non-C++ cases as well. C++ by default will use the name of a function, its parameters and its return type when calculating a name for a function. The linker function name for

void CALLTYPE test(void)

might come to anything in the table below depending on what CALLTYPE is and what language you are using. CALLTYPEs such as __cdecl, __fastcall, and __stdcall can change the naming conventions for a function/variable.

Calling convention | extern “C” or .C file | .CPP , .CXX or /TP
C naming convention (__cdecl) | _test | ?test@@ZAXXZ
Fastcall naming convention (__fastcall) | @test@0 | ?test@@YIXXZ
Standard Call naming convention (__stdcall) | _test@0 | ?test@@YGXXZ

Use extern “C” when calling a C function from a C++ program. Extern “C” forces use of the C naming convention for non-class C++ functions. Be aware of compiler switches like /TP or /Tc that force a file to be compiled as a C (/Tc) or C++ (/TP) file no matter what the filename extension, or you may get different function names than you expect.

Having function prototypes that have mismatched parameters can also cause this error. Name decoration incorporates the parameters of a function into the final decorated function name. Calling a function with the parameter types that do not match those in the function declaration may also cause LNK2001.

There is currently no standard for C++ naming between compiler vendors or even between different versions of a compiler. Therefore linking object files compiled with other compilers may not produce the same naming scheme and thus causes unresolved externals.


The Symbol Is Not Public

Only global functions and variables are placed in the OBJ PST table. Trying to access variables of the types below will often cause Unresolved Externals.

Static functions/variables

Functions declared with the static modifier by definition have file scope. Static variables have the same limitation. Trying to access any static variables from outside of the file in which they are declared can result in a compile error or an unresolved external depending on the specific coding of the source files.

MAIN.CPP

extern void func1(void);

void main(void)
{
 func1();
}

TEST.CPP

static void func1(void)
 {
  //Do something
 }


Automatic (Function Scope) Variables

A variable declared within a function can only be used within the scope of that function.

MAIN.CPP

void test(void);

static int lnktest3 =3;
int lnktest4 =4;

void main()
{
 static int lnktest1 =1;
 int lnktest2 = 2;
 test( );
}

TEST.CPP

extern int lnktest1;
extern int lnktest2;
extern int lnktest3;
extern int lnktest4;

void test(void)
{
  int i =0;
   i = lnktest1;   //causes LNK2001 reason b
   i = lnktest2;   //causes LNK2001   reason b
   i = lnktest3;   //causes LNK2001 reason a
   i = lnktest4;   // OK
}


Global Constants in C++

C++ global constants have static linkage. This is different than C. If you try to use a global constant in C++ in multiple files you get an unresolved external error. Global constants are optimized out by the compiler, leaving no space reserved for the variable. One alternative is to include the const initializations in a header file and include that header in your CPP files when necessary, just as if it was function prototype. Another possibility is to make the variable non-constant and use a constant reference when assessing it. The following code illustrates this error.

MAIN.CPP

void test(void);
const int lnktest1 = 0;

void main(void)
{

test( );

}

TEST.CPP

extern int lnktest1;

void test(void)
{
  int i = lnktest1;   // Causes LNK2001 reason c
}


Function Inlining Problems

If you are using function inlining make sure that you

  • Have the inline functions implemented in the header file you are going to include in other files

  • Have inlining turned ON in the header file.

If you are using the #pragma inline_depth compiler directive, make sure you have a value of 2 or greater set. A value of zero will turn off inlining. Also make sure you are using the /Ob1 or /Ob2 compiler options. These are available in the Project Settings dialog box. (See the "Optimizations" category on the C/C++ tab.)

Mixing inline and non-inline compile options on different modules can sometimes cause problems. If a C++ library is created with function inlining turned on (/Ob1 or /Ob2) but the corresponding header file describing the functions has inlining turned off (no option), you will get error LNK2001. The functions do not get inlined into the code from the header file, but since they are not in the library file there is no address to resolve the reference.

Similarly, a project that uses function inlining yet defines the functions in a .CPP file rather than in the header file will also get error LNK2001. The header file is included everywhere deemed appropriate, but the functions are only inlined when the .CPP file passes through the compiler. Therefore the linker sees the functions as unresolved externals when used in other modules.

TESTCLS.H

class testcls {
 public:
  void PublicStatMemFunc1(void);
};

CLASFUNC.CPP

#include "testcls.h"

inline void testcls::PublicStatMemFunc1(void)
{
}

TEST2.CPP

#include "testcls.h"

void main(void)
{
 testcls testclsObject;
 testclsObject.PublicStatMemFunc1( );   //This needed for compiler to add entry to table of unresolved symbols
                            //Will cause an LNK2001 because this module cannot
 }                         //  see the implementation of PublicStatMemFunc1( );


Linker Tools Error LNK2003

gp relative fixup to symbol not in .sdata "module"

The /Gt value specified when compiling an instance of a type differed from the value specified when compiling the reference to the type. Rebuild the object files with consistent values for /Gt.

This error is followed by fatal error LNK1165.


Linker Tools Error LNK2004

gp relative fixup overflow; sdata section ("section") is too large

The .sdata section was too large. Rebuild using smaller values for /Gt and /GPSIZE.

This error is followed by fatal error LNK1165.


Linker Tools Error LNK2005

symbol already defined in object

The given symbol, displayed in its decorated form, was multiply defined.

Tips

One of the following may be a cause:

  • The most common cause of this error is accidentally linking with both the single-threaded and multithreaded libraries. Ensure that the application project file includes only the appropriate libraries and that any third-party libraries have appropriately created single-threaded or multithreaded versions.

  • The given symbol was a packaged function (created by compiling with /Gy) and was included in more than one file but was changed between compilations. Recompile all files that include the symbol.

  • The given symbol was defined differently in two member objects in different libraries, and both member objects were used.

  • An absolute was defined twice, with a different value in each definition.

This error is followed by fatal error LNK1169.


Linker Tools Error LNK2006

TOC relative fixup to symbol not in TOC "name"; fixup ignored

LINK found an invalid fixup and ignored it.


Linker Tools Error LNK2007

TOC relative fixup overflow; TOC is too large; fixup ignored

LINK found an invalid fixup and ignored it.


Linker Tools Error LNK2008

Fixup target is not aligned "alignment"

LINK found a fixup target in your object file that was not aligned properly.


Linker Tools Error LNK2009

Fixup target must be absolute "name" w/o -FIXED; fixup ignored

LINK found an invalid fixup and ignored it.


Linker Tools Error LNK2010

Duplicate IMGLUE relocations for "name"

LINK found duplicate relocations for "name" in your object file. The object file is probably corrupt.

See Corrupt Object File for more information.


Linker Tools Error LNK2011

precompiled object not linked in; image may not run

If you use precompiled headers, LINK now requires that all of the object files created with precompiled headers must be linked in. If you have a source file that you use to generate a precompiled header for use with other source files, you now must include the object file created along with the precompiled header.

For example, if you compile a file called STUB.CPP to create a precompiled header for use with other source files, you must link with STUB.OBJ or you will get this error. In the following command lines, line one is used to create a precompiled header, COMMON.PCH, that is used with PROG1.CPP and PROG2.CPP in lines two and three. The file STUB.CPP contains only #include lines (the same #include lines as in PROG1.CPP and PROG2.CPP) and is used only to generate precompiled headers. In the last line, STUB.OBJ must be linked in to avoid LNK2011.

cl /c /Yccommon.pch stub.cpp
cl /c /Yucommon.pch prog1.cpp
cl /c /Yucommon.pch prog2.cpp
link /Feprog.exe stub.obj prog1.obj prog2.obj


Linker Tools Error LNK2012

No NOP following relocationtype relocation to "symbol"

TOCINDIRCALL and TOCCALLREL require a NOP following the instruction that has this type of relocation. This is mainly useful for compiler and assembler developers who use the Microsoft linker.


Linker Tools Error LNK2013

Fixup overflow. Target "symbol" is out of range

This error occurs when the executable is too large under either Windows NT or MACOS on PowerPC platforms. For all platforms, the error may indicate a problem with assembly code.

Tips

To work around the problem:

  • Use shared libraries.

  • TOC space is required for global data accessed from a module other than where it is defined. You can eliminate the TOC space by moving such data to the module where it is referenced. However, if data is referenced in multiple modules, then the TOC space cannot be eliminated to save space.


Linker Tools Error LNK2014

TLS relative fixup overflow; .tls section ("section") is too large

The section created for thread-local storage (.tls) is too large. TLS data must fit in 32 KB. This data is created using the __declspec(thread) storage class modifier in the declaration and definition of that data. This error occurs for Power PC/Windows NT platforms.

Tips

To work around the problem:

  • Reduce the amount of thread-local data in the code.

  • Use dynamic TLS by calling functions such as TlsAlloc and TlsFree.


Linker Tools Warning LNK4001

no object files specified; libraries used

The command did not specify any object files as input. The tool used objects from the libraries that were specified as input.


Linker Tools Warning LNK4002

symbol defined in object

The given symbol, displayed in its decorated form, was specified in its undecorated form in object, but a unique match to a decorated symbol could not be found. This warning is always preceded by warning LNK4022 and followed by fatal error LNK1152.


Linker Tools Warning LNK4003

invalid library format; library ignored

The file header for the input library was invalid. The tool did not use the library.


Linker Tools Warning LNK4005

no objects used from library library

The library was specified in the command, but no references were resolved from that library.


Linker Tools Warning LNK4006

symbol already defined in object; second definition ignored

The given symbol, displayed in its decorated form, was multiply defined. When this warning is encountered, symbol will be added twice, but only its first form will be used.

Tips

  • The given symbol may be a packaged function, created by compiling with /Gy. This symbol was included in more than one file but was changed between compilations. Recompile all files that include the symbol.

  • The given symbol may have been defined differently in two member objects in different libraries.

  • An absolute may have been defined twice, with a different value in each definition.

  • If the error message is received when combining libraries, symbol already exists in the library being added to.

If you are rebuilding the C run-time library, you can ignore this message.


Linker Tools Warning LNK4010

invalid version number "number"; default version assumed

Either the major or the minor number in the specified version argument was not valid.

Each part of a version specification must be an integer in the range 1–65535. Options that take a version argument include /SUBSYSTEM and /VERSION.


Linker Tools Warning LNK4011

unknown subsystem "argument"; default assumed

The /SUBSYSTEM option was incorrectly specified. Either no argument was specified or argument did not have the expected syntax. The tool assumed an appropriate default.


Linker Tools Warning LNK4012

invalid value "argument", must be keywords; option ignored

The given argument was not a valid keyword for the option it was specified with. The valid arguments are shown in the given list of keywords.


Linker Tools Warning LNK4013

image size imagesize exceeds specified maximum maxsize

The base address file specified with the /BASE option listed the maximum size of the program as maxsize, but maxsize was less than the resulting image size of the program.


Linker Tools Warning LNK4014

cannot find member object "objectname"

LIB could not find objectname in the library.

The /REMOVE and /EXTRACT options require the full name of the member object that is to be deleted or copied to a file. The full name includes the path of the original object file. To see the full names of member objects in a library, use DUMPBIN /ARCHIVEMEMBERS or LIB /LIST.


Linker Tools Warning LNK4015

memorytype commit exceeds reserve; commit size set to size

The value specified for the commit size for the memorytype exceeded the value specified for the reserve size. The tool assumed size as the value of the commit size.


Linker Tools Warning LNK4017

keyword statement not supported for the target platform; ignored

The given module-definition statement is not supported by this version of the linker tools. The tool ignored the statement in the .DEF file.


Linker Tools Warning LNK4018

too many type indexes in PDB "filename", discarding subsequent type information

There are more than 64K type indexes in the program database (PDB). The PDB might contain unneeded type information. Delete the existing PDB and rebuild. If the warning persists, then compile some modules without debugging information.


Linker Tools Warning LNK4019

corrupt string table (table end); new end assumed

The object file is corrupt. The tool attempted to correct the problem.

To prevent this warning, rebuild the object file.

See Corrupt Object File for more information.


Linker Tools Warning LNK4022

cannot find unique match for symbol "symbol"

LINK or LIB found multiple matches for the given undecorated symbol and it could not resolve the ambiguity. No output file (.EXE, .DLL, .EXP, or .LIB) is produced. This warning is followed by one warning LNK4006 for each duplicate symbol and is finally followed by fatal error LNK1152.

To prevent this warning, specify the symbol in its decorated form. Run DUMPBIN on the object to see decorated names.


Linker Tools Warning LNK4023

base address address not a 64K multiple; assumed newaddress

The base address specified with the /BASE option must be a multiple of 64K. The tool assumed a newaddress value for the base address.


Linker Tools Warning LNK4027

CVPACK error

LINK called CVPACK to process the debugging information, but one of the following occurred:

  • The call failed. Be sure that CVPACK is in a directory specified in the PATH environment variable and that there is sufficient memory.

  • CVPACK issued an error. Errors generated by CVPACK have the form CKnnnn.


Linker Tools Warning LNK4028

option option is obsolete; ignored

The given option is not supported. LINK ignored the option and continued the build.


Linker Tools Warning LNK4030

invalid file offset number for category; category not dumped

DUMPBIN could not display information for the given category. Probably the file is invalid or corrupt.

See Corrupt Object File for more information.


Linker Tools Warning LNK4031

no subsystem specified; CONSOLE assumed

The /SUBSYSTEM option was not specified, and LINK was not able to determine a subsystem from the input files.


Linker Tools Warning LNK4033

converting object format from OMF to COFF

The format of the object file is OMF. This tool requires COFF input.

To permanently convert the file, run EDITBIN on the file with no options.


Linker Tools Warning LNK4037

"symbol" does not exist; ignored

The symbol could not be ordered using the /ORDER option because it could not be found in the program. Check the specification of symbol in the ordering file.

Note LINK cannot order static functions because static function names are not public symbol names. When /ORDER is specified, this linker warning is generated for each symbol, in the order file, that is either static or not found.


Linker Tools Warning LNK4038

displaying raw data in number units per line

The /RAWDATA option was specified without a formatting argument. DUMPBIN assumed a format value of number units per line of the specified or assumed data type, as follows:

Data Type | number
none | 16
BYTES | 16
SHORTS | 8
LONGS | 4


Linker Tools Warning LNK4039

section "name" specified with /SECTION option does not exist

DUMPBIN or EDITBIN could not find a section called name in the input file.

To see the sections in a file, run DUMPBIN with the /HEADERS option.


Linker Tools Warning LNK4040

corrupt string table (size); string table ignored

The string table in the object file is corrupt. The program may not run as expected. Rebuild the object file.

See Corrupt Object File for more information.


Linker Tools Warning LNK4041

no edit options specified

EDITBIN was run on the input file, but no options were used.

If the file format was not COFF, EDITBIN attempted to convert it. Otherwise, EDITBIN took no action on the file.


Linker Tools Warning LNK4042

object specified more than once; extras ignored

The same object file was specified more than once in the LINK or LIB command. The result is the same as if the file were specified only the first time.


Linker Tools Warning LNK4043

invalid /ALIGN value number (must be power of 2); assumed default

The argument specified with the /ALIGN option was not a power of 2.


Linker Tools Warning LNK4044

unrecognized option "option"; ignored

The given option is not a valid option for this tool. The tool ignored the option.

To see a list of valid options, run the tool with no arguments or options.


Linker Tools Warning LNK4045

creating LINK_REPRO test case in dir "directory"

The LINK_REPRO environment variable, when set, specifies a directory where the linker will copy object files, libraries, and other files. Microsoft can use these files to recreate internal linker errors.

The linker will only copy files if LINK_REPRO is set. If this is not what you want to do, remove the LINK_REPRO environment variable by typing the following:

set LINK_REPRO=


Linker Tools Warning LNK4046

LINK_REPRO is set to current directory; ignored

The LINK_REPRO environment variable should not be set to the current directory. Create a new directory, set LINK_REPRO to the new directory, and rerun the linker.


Linker Tools Warning LNK4047

cannot edit library file "filename"; ignored

EDITBIN cannot process a library file.


Linker Tools Warning LNK4048

Invalid format file; ignored

EDITBIN could not process the file because it was not a valid object file, executable file, or dynamic-link library (DLL).


Linker Tools Warning LNK4049

exported symbol "symbol" also imported

The symbol was both exported from and imported to the program.

This warning is displayed when the LINK warning level (set by the /WARN option) is greater than 1.


Linker Tools Warning LNK4051

extra delimiter in /EXPORT specification

The specification of the /EXPORT option ended with a comma (,).


Linker Tools Warning LNK4052

using .EXP file; ignoring .DEF file "filename"

The .DEF file specified in the LINK command was ignored because an .EXP file was also specified. The .DEF file was already processed when the .EXP file was created and is not necessary in this step of the build process.


Linker Tools Warning LNK4055

invalid fixup found, address address; fixup ignored

The object contained an invalid fixup. The resulting executable file will probably not run correctly.

Rebuild the object file.

See Corrupt Object File for more information.


Linker Tools Warning LNK4056

extra arguments ignored for option "option"

The option was specified with too many arguments. The additional arguments were ignored.


Linker Tools Warning LNK4057

"library1" should precede "library2" in the link command line

Check the order of your libraries.

The developer of library1 determined that it should be searched by the linker before library2. For example, library1 might contain an updated version of a function in library2. If you specify library2 first, the linker will link in the old version rather than the newer version from library1.


Linker Tools Warning LNK4059

resourcefile already specified; additional resource file ignored

Only one resource file is allowed. The first .RES file specified in the command was used.


Linker Tools Warning LNK4060

stub file missing full MS-DOS header; rebuild stub with /KNOWEAS 16-bit LINK option

The MS-DOS application specified with the /STUB option does not have a full 40-byte header. The stub program may not run as expected.

To rebuild the 16-bit stub with a full 40-byte header, use the undocumented /KNOWEAS option with the 16-bit LINK version 5.5x or higher.


Linker Tools Warning LNK4061

/NOSTUB ignored because no DOS stub is present

EDITBIN could not remove the stub file because it could not find one in your executable file.


Linker Tools Warning LNK4062

"option" not compatible with "platform" target machine; option ignored

The given option is not supported for the target platform of this build. LINK ignored the option and continued the build.


Linker Tools Warning LNK4064

conflicting subsystem; image may not run

You tried to link in a library whose subsystem differs from your executable’s subsystem value, and your executable file may not run. For more information on subsystems, see the /SUBSYSTEM linker option and Managing a Library.

Note You will not receive this warning if one subsystem is CONSOLE and the the other’s subsystem is WINDOWS.


Linker Tools Warning LNK4065

"function" cannot be ordered; ignored

The given function was not compiled as a packaged function. Recompile using /Gy.


Linker Tools Warning LNK4066

DLL contains .sdata section

One or more objects was compiled using /Gt. Objects compiled with /Gt cannot be used to create a DLL.


Linker Tools Warning LNK4067

ambiguous entry point; selected "entry"

LINK found multiple entry points for the program. It assumed the given entry.


Linker Tools Warning LNK4068

/MACHINE not specified; defaulting to machinetype

LINK did not find a machine specification. It assumed the given machine type. If the default is incorrect, resulting in fatal error LNK1112, relink using the /MACHINE option.


Linker Tools Warning LNK4069

cannot create map and/or checksum image; checksum set to 0

This warning can occur if IMAGEHLP.DLL is not available.


Linker Tools Warning LNK4070

/OUT:filename directive in .EXP differs from output filename "filename"; ignoring directive

The filename specified in the NAME or LIBRARY statement when the .EXP file was created differs from the output filename that was either assumed by default or specified with the /OUT option.

A client program that uses the resulting DLL might encounter problems.


Linker Tools Warning LNK4071

cannot be incrementally linked on subsequent links

LINK found multiple definitions for one or more symbols, but /FORCE or /FORCE:MULTIPLE was used to create an output file regardless of errors. LINK deleted the incremental status (.ILK) file.


Linker Tools Warning LNK4072

section count count exceeds max (number); image may not run

The number of sections (a COFF .EXE or .DLL file is composed of sections, similar to segments) in the output file is greater than the limit that can be handled by the loader.

You can define your own sections using the data_seg, code_seg, and alloc_text pragmas. For example, the following program defines three sections called .a1, .a2, and .a3.

#pragma data_seg(".a1")
int a1 = 1;
#pragma data_seg(".a2")
int a2 = 2;
#pragma data_seg(".a3")
int a3 = 3;

void main (void) {
   ;
}

You can view the names of the sections in your executable file by using the DUMPBIN program with the default /SUMMARY option. See the DUMPBIN Reference for more information.

To reduce the number of sections in your executable file:

  • Remove unneeded data_seg, code_seg or alloc_text pragmas. See data_seg, code_seg, and alloc_text.

  • Use the /MERGE option with LINK to combine sections. See /MERGE.


Linker Tools Warning LNK4073

cannot create map for .ILK file; linking nonincrementally

There was not a large enough contiguous space in shared memory for LINK to create the incremental status (.ILK) file. LINK performed a nonincremental build.


Linker Tools Warning LNK4074

unable to load filename; cannot checksum

The linker tried to load the dynamic-link library filename but could not. A function in filename is used to checksum the executable file.

One of the following may be a cause:

  • The linker could not find filename because it is not in the current directory or in a directory in the PATH environment variable.

  • There was a problem with filename. Recopy filename from the installation disks.


Linker Tools Warning LNK4075

ignoring "option1" due to "option2" specification

The option2 specification overrides option1.


Linker Tools Warning LNK4076

invalid incremental status file "filename"; linking nonincrementally

LINK cannot write to the incremental status (.ILK) file. Either filename is corrupt or it is not an incremental linking database. Remove the file and relink.


Linker Tools Warning LNK4077

exports file "filename" used; ignoring other export specifications

The given exports file provides the program's exports. Exports specified by the /EXPORT option or the EXPORTS statement in a .DEF file were ignored.


Linker Tools Warning LNK4078

multiple "section" sections found with different attributes

LINK found two or more sections that have the same name but different attributes. Probably an import library or exports file was created by a previous version of LINK or LIB. Recreate the file and relink.


Linker Tools Warning LNK4079

no write permission for incremental status file "filename"; linking nonincrementally

LINK cannot write to the incremental status (.ILK) file because filename does not have the correct permissions.


Linker Tools Warning LNK4081

insufficient disk space; linking nonincrementally

There is not enough space on disk for LINK to create or write to the incremental status (.ILK) file.


Linker Tools Warning LNK4082

unable to find entrypoint function in module; cannot checksum

The function CheckSumMappedFile() does not exist in IMAGEHLP.DLL.


Linker Tools Warning LNK4083

module "name" does not exist; ignored

The module "name" you gave in your order file does not exist. Check the spelling.

For more information on order files, see the /ORDER linker option.


Linker Tools Warning LNK4084

total image size size exceeds max (256MB); image may not run

The application exceeds the limit of 256 megabytes.


Linker Tools Warning LNK4085

more than number comments; skipping exestr

This warning occurs when the linker tool is converting an OMF object to a COFF object. It indicates there are more than 256 comments in the OMF module. For more information about comment strings, see #pragma comment in Preprocessor Reference.


Linker Tools Warning LNK4086

entrypoint 'function' is not __stdcall with 12 bytes of arguments; image may not run

The entry point for a DLL must be __stdcall. Either recompile the function with the /Gz option or specify __stdcall or WINAPI when you define the function.


Linker Tools Warning LNK4087

CONSTANT keyword is obsolete; use DATA

This warning occurs if you use CONSTANT with your exports in a module definition file or on the command line. Use DATA instead.


Linker Tools Warning LNK4088

image being generated due to /FORCE option; image may not run

The linker encountered an error. Normally it deletes the image it created because the image may not run due to the error. Since you used the /FORCE option, however, the linker did not remove the image.


Linker Tools Warning LNK4089

all references to "dynamic-link library" discarded by /OPT:REF

The linker discarded all packaged functions that referenced exports in dynamic-link library. As a result, dynamic-link library and its import library are unneeded.


Linker Tools Warning LNK4090

No IFGLUE relocation in module with branch to glue code "name"

Your object file contained bad relocation information. Recopy or recreate the object file.

See Corrupt Object File for more information.


Linker Tools Warning LNK4092

shared section "section" contains relocations; image may not run correctly

The linker emits this warning whenever you have a shared section to warn you of a potentially serious problem.

One way to share data between multiple processes is to mark a section as “shared.” Marking a section as shared can cause problems, however. For example, you have a DLL that contains declarations like this in a shared data section:

int var = 1;
int *pvar = &var;

The linker cannot resolve pvar because its value depends on where the DLL is loaded in memory, so it puts a relocation record in the DLL. When the DLL is loaded into memory, the address of var can be resolved and pvar assigned. If another process loads the same DLL but cannot load it at the same address, the relocation for the address of var will be wrong because the relocation was applied for the first process's address space.


Linker Tools Warning LNK4093

Drive/Directory component ignored in "module-definition" statement

Your module-definition (.DEF) file used a statement incorrectly. The LIBRARY or NAME statements cannot contain directory or drive information. See Module-Definition Files for more information.


Linker Tools Warning LNK4094

filename is an MS-DOS executable; use EXEHDR to dump it

The DUMPBIN program only works with COFF-format executable files. Use EXEHDR on MS-DOS executables. EXEHDR is included with Visual C++ 1.5.


Linker Tools Warning LNK4095

filename is an NE format executable; use EXEHDR to dump it

The DUMPBIN program only works with COFF-format executable files. Use EXEHDR on NE format executables. EXEHDR is included with Visual C++ 1.5.


Linker Tools Warning LNK4096

/BASE value "number" is invalid for Windows 95; image may not run

The base address you specified is invalid. Windows 95 executable files must have a base address greater than 0x400000. For more information on base addresses, see the /BASE linker option.


Linker Tools Warning LNK4097

duplicate name "name" in order file; using last one

Order files specify the order you want the linker to load your functions. In your order file, a function appears more than once, so the linker ignored all references to it except the last.

For more information on order files, see the /ORDER linker option.


Linker Tools Warning LNK4098

defaultlib "library" conflicts with use of other libs; use /NODEFAULTLIB:library

You are trying to link with incompatible libraries.

Important The run-time libraries now contain directives to prevent mixing different types. You’ll receive this warning if you try to use different types or debug and non-debug versions of the run-time library in the same program. For example, if you compiled one file to use one kind of run-time library and another file to use another kind (for example, single-threaded versus multithreaded) and tried to link them, you’ll get this warning. You should compile all source files to use the same run-time library. See the Use Run-Time Library (MD, /ML, /MT, /LD) compiler options for more information.

You can use the linker’s /VERBOSE:LIB switch to determine which libraries the linker is searching. If you receive LNK4098 and want to create an executable file that uses, for example, the single-threaded, non-debug run-time libraries, use the /VERBOSE:LIB option to find out which libraries the linker is searching. The linker should print LIBC.LIB and not LIBCMT.LIB, MSVCRT.LIB, LIBCD.LIB, LIBCMTD.LIB, or MSVCRTD.LIB as the libraries searched. You can tell the linker to ignore the the incorrect run-time libraries by typing the incorrect libraries in the Ignore Libraries text box on the Link tab of the Settings dialog box in Developer’s Studio or by using the /NODEFAULTLIB:library option with LINK for each library you want to ignore. See the Ignore Libraries (/NODEFAULTLIB) linker option for more information.

The table below shows which libraries should be ignored depending on which run-time library you want to use.

To use this run-time library | Ignore these libraries
Single-threaded (libc.lib) | libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
Multithreaded (libcmt.lib) | libc.lib, msvcrt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
Multithreaded using DLL (msvcrt.lib) | libc.lib, libcmt.lib, libcd.lib, libcmtd.lib, msvcrtd.lib
Debug Single-threaded (libcd.lib) | libc.lib, libcmt.lib, msvcrt.lib, libcmtd.lib, msvcrtd.lib
Debug Multithreaded (libcmtd.lib) | libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, msvcrtd.lib
Debug Multithreaded using DLL (msvcrtd.lib) | libc.lib, libcmt.lib, msvcrt.lib, libcd.lib, libcmtd.lib

For example, if you received this warning and you want to create an executable file that uses the non-debug, single-threaded version of the run-time libraries, you could use the following options with the linker:

/NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:msvcrt.lib /NODEFAULTLIB:libcd.lib /NODEFAULTLIB:libcmtd.lib /NODEFAULTLIB:msvcrtd.lib


Linker Tools Warning LNK4099

PDB "filename" was not found with "object/library" or at "path"; linking object as if no debug info

The linker was unable to find your .PDB file. Copy it into the directory that contains object/library.


Linker Tools Warning LNK4102

export of deleting destructor <symbol name>; image may not run correctly

The program has attempted to export a deleting destructor. The resulting delete may occur across a DLL boundary such that a process can free memory that it does not own. Make sure that the given symbol is not listed in your .DEF file, and that the symbol is not listed as an argument of the /IMPORT or /EXPORT option in the linker command line.

If you are rebuilding the C run-time library, you can ignore this message.


Linker Tools Warning LNK4103

import of deleting destructor "symbol name"; image may not run correctly

The program has attempted to import a deleting destructor. The resulting delete may occur across a DLL boundary such that a process can free memory that it does not own. Make sure that the given symbol is not listed in your .DEF file, and that the symbol is not listed as an argument of the /IMPORT or /EXPORT option in the linker command line.


Linker Tools Warning LNK4104

export of symbol "symbol" should be PRIVATE

The symbol can be one of the following:

  • DllRegisterServer

  • DllRegisterServerEx

  • DllUnregisterServer

  • DllGetClassObject

  • DllCanUnloadNow

This warning is emitted when you are building an import library for a DLL and export one of the above functions without specifying it as PRIVATE in the module-definition file. In general these functions are exported for use only by OLE. Placing them in the import library can lead to unusual behavior when a program linked to the library incorrectly makes calls to them.


Linker Tools Warning LNK4105

no argument specified with option option; ignoring switch

This warning occurs only when the /LIBPATH option is set. If no directory is specified with this option, then the linker ignores this option and generates this warning message.

If you do not need to override the existing environmental library settings, remove the /LIBPATH option from the linker command line. If you want to use an alternate search path for libraries, specify the alternate path following the /LIBPATH option. For example:

link /libpath:c:\foo\lib bar.obj

would direct the linker to search for the required libraries in c:\foo\lib before searching in the default locations.


Linker Tools Warning LNK4106

"section name" section discarded due to "option" specification

The option caused the linker to discard the section.


Linker Tools Warning LNK4107

"/option" not supported by this version of MSPDB60.DLL; ignored

MSPDB60.DLL does not support the specified option.


Linker Tools Warning LNK4108

/ALIGN specified without /DRIVER or /VXD; image may not run

The /ALIGN option has been specified without also specifying either /DRIVER or /VXD.

Bad alignment can prevent the operating system from loading the final image. Do not use the /ALIGN option unless building a driver or vxd.


Linker Tools Warning LNK4194

/DELAYLOAD:dll name ignored

The linker cannot delay load the requested DLL.


Linker Tools Warning LNK4195

unable to load dll name

The linker could not load the requested DLL.


Linker Tools Warning LNK4197

export "exportname" specified multiple times; using first specification

An export is specified in multiple, different ways. The linker uses the first specification and ignores the rest.

Perhaps the same export is specified both on the command line (via export:) and in the .def file or listed twice in the .def file with different attributes.

If an export is specified exactly the same way multiple times, the linker will not issue a warning.

For example, the following contents of a .def file would cause this warning:

EXPORTS
   functioname      NONAME
   functioname      @10


Linker Tools Warning LNK4198

base key "keyname" not found - using default

The keyname, specified in a /BASE option, does not appear in the base address file.


Linker Tools Warning LNK4199

/DELAYLOAD:dllname ignored; no imports found from dllname

The linker ignores dllname because it does not need any of the functions that dllname exports.


Linker Tools Warning LNK4200

corrupt line number information in object file; ignored

The line number information in the object file has become corrupted. Rebuild.


Linker Tools Warning LNK4543

Section "section" with invalid attributes ignored

The linker could not determine the type of section and ignored it. Valid types for sections include text, data, bss, and rdata.


Linker Tools Warning LNK4544

Symbol "symbol" specified with /IMPORT not referenced in application - ignored

You specified a symbol with the /IMPORT option but it was not referenced in your program so the linker ignored it.


Linker Tools Warning LNK4545

Container "container" specified with /IMPORT not referenced in application - ignored

You specified an import library (container) with the /IMPORT option, but your program did not reference the library. The linker ignored the container.


Linker Tools Warning LNK4546

Mismatch in versions detected. Container may not load. Use /VERBOSE for details.

The linker detected a problem with versions in your import libraries (containers). To find out which container (and its version number) is causing the problem, rerun LINK with the /VERBOSE option.


Linker Tools Warning LNK4547

Setting "versiontype" to version

The linker set versiontype to version. Possible values for versiontype are CURRENTVER, OLDCODEVER, and OLDAPIVER.


Linker Tools Warning LNK4548

Ignoring "versiontype" version

The linker ignored version information of versiontype. The possible values of versiontype are CURRENTVER, OLDCODEVER, and OLDAPIVER.


Linker Tools Warning LNK4549

shared library "library" does not have any exports

The shared library was ignored since it contained no exports.


Linker Tools Warning LNK6001

insufficient disk space; performing full link

There was not enough space on disk for LINK to incrementally link the program. LINK attempted to correct the problem and recover disk space by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6002

invalid .ILK file found; performing full link

The incremental status (.ILK) file was not valid. Probably the previous incremental linking session was interrupted. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6003

LINK options changed; performing full link

The options specified to the linker differed from the options used during the previous incremental linking session. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6004

filename not found or not built by the last incremental link; performing full link

The given file was either deleted or changed since the last incremental linking session. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6005

exports changed; performing full link

One or more exports were added or deleted since the last incremental linking session. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6006

program database pdbname missing; performing full link

LINK could not find the program database (.PDB) file that it created during the last incremental linking session. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6008

object file added; performing full link

An object file was added since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6009

object file removed; performing full link

An object file was removed since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6010

library changed; performing full link

A library was modified since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6011

internal limit exceeded; performing full link

An internal limit related to incremental linking was exceeded. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.

One cause of this warning is an .ILK file that exceeds 8MB. If this size is due to the accumulation of dead space, that space will be recovered in a full link.


Linker Tools Warning LNK6012

precompiled types found; performing full link

An object file was compiled with /Z7 and the program used a precompiled header. LINK attempted to incrementally link by running a full link to recreate the incremental status (.ILK) file.

Rebuild the object file with /Zi.


Linker Tools Warning LNK6013

padding exhausted: performing full link

An internal limit related to incremental linking was exceeded. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6014

symbol reference set changed; performing full link

A reference to a symbol in a library was added since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6015

bss (uninitialized data) change; performing full link

A bss symbol was changed since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6016

absolute symbol changed; performing full link

The address of an absolute symbol was changed since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6017

set of library modules referenced changed; performing full link

A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6018

multiple definitions found for "symbol"; performing full link

A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6019

directive changed; performing full link

A directive was added or deleted since the last incremental linking session. A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6020

ILK file not built by this linker; performing full link

The version number of the .ILK file was incorrect for this version of LINK. LINK attempted to correct the problem by running a full link to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6021

performing full link

A full link was required in order to create the incremental status (.ILK) file.


Linker Tools Warning LNK6022

unable to load .ILK file; performing full link

The .incremental status (.ILK) file is unavailable because of the actions of another process.


Linker Tools Warning LNK6023

unable to extend map for .ILK file; performing full link

The .incremental status (.ILK) file cannot be written to because of the actions of another process.


Linker Tools Warning LNK6024

Mac Resource File "filename" changed; performing full link

A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6025

unable to do comdat selection; performing full link

A full link was required in order to recreate the incremental status (.ILK) file.


Linker Tools Warning LNK6026

obsolete DBI format found; performing full link

A full link was required. The format of debugging information changed between Visual C++ versions 4.0 and 4.1. Code that was initially linked with version 4.0 and that is now linked with a later version thus has inconsistent debugging information. Therefore, a full link was performed to rectify the inconsistency.


Corrupt Object File

Sometimes the linker is unable to process your object files because they are corrupt. Besides the usual causes of corrupt files such as network problems or exposing a floppy disk to a magnetic field, sometimes the compiler writes an incorrect object file, which you should report to Microsoft Product Support Services. See the Technical Support command on the Help menu for more information.

After you have ruled out a hardware, operating system, or network problem as the cause of the corrupt object file, you should try the tips below because sometimes by changing compiler options and recompiling, the compiler will write a non-corrupt object file.

Here are some things to try when recompiling:

  • Turn off optimization with the /Od (Disable) option.

  • Disable incremental compilation with the /Gi– (Enable Incremental Compilation) option.

  • Disable minimal rebuild with the /Gm– (Enable Minimal Rebuild) option.

  • Compile with the /Gy (Enable Function-Level Linking) option to package functions.

  • Use a different code generation option. See the /G (Optimize for Processor) options.

  • Change the order of functions and global variables.


Math Errors M6101 through M6205

The following topics cover math errors M6101 through M6205.


Math Error M6101

invalid

An invalid operation occurred. This error usually occurs when the operand is NaN (not a number) or infinity.

This error terminates the program with exit code 129.


Math Error M6102

denormal

A very small floating-point number was generated, which may no longer be valid because of a loss of significance. Denormal floating-point exceptions are usually masked, causing them to be trapped and operated upon.

This error terminates the program with exit code 130.


Math Error M6103

divide by 0

A floating-point operation attempted to divide by zero.

This error terminates the program with exit code 131.


Math Error M6104

overflow

An overflow occurred in a floating-point operation.

This error terminates the program with exit code 132.


Math Error M6105

underflow

An underflow occurred in a floating-point operation. Underflow floating-point exceptions are usually masked, causing the underflowing value to be replaced by 0.0.

This error terminates the program with exit code 133.


Math Error M6106

inexact

Loss of precision occurred in a floating-point operation. This exception is usually masked. Many floating-point operations cause a loss of precision.

This error terminates the program with exit code 134.


Math Error M6107

unemulated

An attempt was made to execute a coprocessor instruction that is invalid or is not supported by the emulator.

This error terminates the program with exit code 135.


Math Error M6108

square root

The operand in a square-root operation was negative.

This error terminates the program with exit code 136.

Note The sqrt function in the C run-time library and the FORTRAN intrinsic function SQRT do not generate this error. The C sqrt function checks the argument before performing the operation and returns an error value if the operand is negative. The FORTRAN SQRT function generates the DOMAIN error M6201 instead of this error.


Math Error M6110

stack overflow

A floating-point expression caused a stack overflow on the 8087/287/387 coprocessor or the emulator.

Stack-overflow floating-point exceptions are trapped up to a limit of seven levels in addition to the eight levels usually supported by the 8087/287/387 coprocessor.

This error terminates the program with exit code 138.


Math Error M6111

stack underflow

A floating-point operation resulted in a stack underflow on the 8087/287/387 coprocessor or the emulator.

This error is often caused by a call to a long double function that does not return a value. For example, the following generates this error when compiled and run:

long double ld() {};
main ()
{
  ld();
}

This error terminates the program with exit code 139.


Math Error M6201

'function' : _DOMAIN error

An argument to the given function was outside the domain of legal input values for that function.

For example, the following statements generate this error:

result = sqrt(-1.0)   // C statement
result = SQRT(-1.0)   !  FORTRAN statement

This error calls the _matherr function with the function name, its arguments, and the error type. You can rewrite the _matherr function to customize the handling of certain run-time floating-point math errors.


Math Error M6202

'function' : _SING error

An argument to the given function was a singularity value for this function. The function is not defined for that argument.

For example, in FORTRAN the following statement generates this error:

result = LOG10(0.0)

This error calls the _matherr function with the function name, its arguments, and the error type. You can rewrite the _matherr function to customize the handling of certain run-time floating-point math errors.


Math Error M6203

'function' : _OVERFLOW error

The given function result was too large to be represented.

This error calls the _matherr function with the function name, its arguments, and the error type. You can rewrite the _matherr function to customize the handling of certain run-time floating-point math errors.


Math Error M6205

'function' : _TLOSS error

A total loss of significance (precision) occurred.

This error may be caused by giving a very large number as the operand of sin, cos, or tan because the operand must be reduced to a number between 0 and 2*pi.


NMAKE Errors U1000 through U4011

The following topics cover NMAKE Error U1000 through Warning U4011.


NMAKE Fatal Error U1000

syntax error : ')' missing in macro invocation

A left parenthesis, (, appeared without a matching right parenthesis, ), in a macro invocation. The correct form is $(name); $n is allowed for one-character names.


NMAKE Fatal Error U1001

syntax error : illegal character 'character' in macro

The given character appeared in a macro but was not a letter, number, or underscore (_).

If the colon (:) is omitted in a macro expansion, the following error occurs:

syntax error : illegal character '=' in macro


NMAKE Fatal Error U1002

syntax error : invalid macro invocation '$'

A single dollar sign ($) appeared without a macro name associated with it.

The correct form is $(name). To specify a dollar sign, use a double dollar sign ($$) or precede the dollar sign with a caret (^).


NMAKE Fatal Error U1003

syntax error : '=' missing in macro

A macro invocation contained a colon (:), which begins a substitution, but it did not contain an equal sign (=).

The correct form is:

$(macroname:oldstring=newstring)


NMAKE Fatal Error U1004

syntax error : macro name missing

One of the following occurred:

  • The name of a macro being defined was itself a macro invocation that expanded to nothing. For example, if the macro named ONE is undefined or has a null value, the following macro definition causes this error:
    $(ONE)=TWO
  • A macro invocation did not specify a name in the parentheses. The following specification causes this error:
    $()

The syntax for using a macro is:

$(name)


NMAKE Fatal Error U1005

syntax error : text must follow ':' in macro

A string substitution was specified for a macro, but the string to be changed in the macro was not specified.


NMAKE Fatal Error U1006

syntax error : missing closing double quotation mark

An opening double quotation mark (") appeared without a closing double quotation mark.


NMAKE Fatal Error U1007

double quotation mark not allowed in name

The specified target name or filename contained a double quotation mark (").

Double quotation marks can surround a filename but cannot be contained within it.


NMAKE Fatal Error U1017

unknown directive '!directive'

The specified directive is not one of the recognized directives.


NMAKE Fatal Error U1018

directive and/or expression part missing

The directive was incompletely specified.

The expression part of the directive is required.


NMAKE Fatal Error U1019

too many nested !IF blocks

The limit on nesting of !IF directives was exceeded.

The !IF preprocessing directives include !IF, !IFDEF, !IFNDEF, !ELSE IF, !ELSE IFDEF, and !ELSE IFNDEF.


NMAKE Fatal Error U1020

end-of-file found before next directive

An expected directive was missing.

For example, an !IF was not followed by an !ENDIF.


NMAKE Fatal Error U1021

syntax error : !ELSE unexpected

An !ELSE directive was found that was not preceded by an !IF directive, or the directive was placed in a syntactically incorrect place.

The !IF preprocessing directives include !IF, !IFDEF, !IFNDEF, !ELSE IF, !ELSE IFDEF, and !ELSE IFNDEF.


NMAKE Fatal Error U1022

missing terminating character for string/program invocation : 'char'

One of the following occurred:

  • The closing double quotation mark (") in a string comparison in a directive was missing.

  • The closing bracket (]) in a program invocation in a directive was missing.


NMAKE Fatal Error U1023

syntax error in expression

An expression was invalid.

Check the allowed operators and operator precedence.


NMAKE Fatal Error U1024

illegal argument to !CMDSWITCHES

An unrecognized command switch was specified.


NMAKE Fatal Error U1025

syntax error : !ENDIF unexpected

An !ENDIF directive was found that was not preceded by an !IF directive, or the directive was placed in a syntactically incorrect place.

The !IF preprocessing directives include !IF, !IFDEF, !IFNDEF, !ELSE IF, !ELSE IFDEF, and !ELSE IFNDEF.


NMAKE Fatal Error U1031

filename missing (or macro is null)

An !INCLUDE directive was found, but the name of the file to be included was missing or a macro representing the filename expanded to nothing.


NMAKE Fatal Error U1033

syntax error : 'string' unexpected

The given string is not part of the valid syntax for a makefile.

The following are examples of causes and results of this error:

  • If the closing set of angle brackets (<<) for an inline file are not at the beginning of a line, the following error occurs:
    syntax error : 'EOF' unexpected
  • If a macro definition in the makefile contained an equal sign (=) without a preceding name or if the name being defined is a macro that expands to nothing, the following error occurs:
    syntax error : '=' unexpected
  • If the semicolon (;) in a comment line in TOOLS.INI is not at the beginning of the line, the following error occurs:
    syntax error : ';' unexpected
  • If the makefile has been formatted by a word processor, the following error can occur:
    syntax error : ':' unexpected


NMAKE Fatal Error U1034

syntax error : separator missing

The colon (:) that separates targets and dependents is missing.


NMAKE Fatal Error U1035

syntax error : expected ':' or '=' separator

Either a colon (:) or an equal sign (=) was expected.

Possible causes include the following:

  • A target was not followed by a colon.

  • A single-letter target was followed by a colon and no space (such as a:). NMAKE interpreted it as a drive specification.

  • An inference rule was not followed by a colon.

  • A macro definition was not followed by an equal sign.

  • A character followed a backslash (\) that was used to continue a command to a new line.

  • A string appeared that did not follow any NMAKE syntax rule.

  • The makefile was formatted by a word processor.


NMAKE Fatal Error U1036

syntax error : too many names to left of '='

Only one string is allowed to the left of a macro definition.


NMAKE Fatal Error U1037

syntax error : target name missing

A colon (:) was found before a target name was found.

At least one target is required.


NMAKE Fatal Error U1038

internal error : lexer

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


NMAKE Fatal Error U1039

internal error : parser

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


NMAKE Fatal Error U1040

internal error : macro expansion

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


NMAKE Fatal Error U1041

internal error : target building

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


NMAKE Fatal Error U1042

internal error : expression stack overflow

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


NMAKE Fatal Error U1043

internal error : temp file limit exceeded

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


NMAKE Fatal Error U1045

spawn failed : message

A program or command called by NMAKE failed for the given reason.


NMAKE Fatal Error U1047

argument before ')' expands to nothing

The parentheses following the preprocessing operator DEFINED or EXIST either were empty or contained an argument that evaluated to a null string.


NMAKE Fatal Error U1048

cannot write to file 'filename'

NMAKE could not write to the given file.

One cause of this error is a read-only file specified with /X.


NMAKE Fatal Error U1049

macro or inline file too long (maximum : 64K)

An inline file or a macro exceeded the limit of 64K.


NMAKE Fatal Error U1050

message

The message specified with the !ERROR directive was displayed.


NMAKE Fatal Error U1051

out of memory

NMAKE ran out of memory, including virtual memory, because the makefile was too large or complex.

One of the following may be a solution:

  • Free some space on disk.

  • Increase the size of the Windows NT paging file or the Windows swap file.

  • If only part of the makefile is being used, either divide the makefile into separate files or use !IF preprocessing directives to limit the amount that NMAKE must process. The !IF directives include !IF, !IFDEF, !IFNDEF, !ELSE IF, !ELSE IFDEF, and !ELSE IFNDEF.


NMAKE Fatal Error U1052

file 'filename' not found

NMAKE could not find the given file, which was specified with one of the following:

  • /F option

  • !INCLUDE preprocessing directive

  • At sign (@) specifier for a response file

Check that the file exists and the filename is spelled correctly.


NMAKE Fatal Error U1053

file 'filename' unreadable

The file cannot be read.

One of the following may be a cause:

  • The file is in use by another process.

  • A bad area exists on disk.

  • A bad file-allocation table exists.


NMAKE Fatal Error U1054

cannot create inline file 'filename'

NMAKE failed to create the given inline file.

One of the following may be a cause:

  • A file by that name exists with a read-only attribute.

  • The disk is full.


NMAKE Fatal Error U1055

out of environment space

The operating system ran out of room for environment variables.

Either increase the environment space or set fewer environment variables.


NMAKE Fatal Error U1056

cannot find command processor

The command processor was not in the path specified in the COMSPEC or PATH environment variables.

NMAKE uses COMMAND.COM or CMD.EXE as a command processor when executing commands. It looks for the command processor first in the path set in COMSPEC. If COMSPEC does not exist, NMAKE searches the directories specified in PATH.


NMAKE Fatal Error U1057

cannot delete temporary file 'filename'

NMAKE failed to delete the temporary inline file.


NMAKE Fatal Error U1058

terminated by user

NMAKE was halted by CTRL+C or CTRL+BREAK.


NMAKE Fatal Error U1059

syntax error : '}' missing in dependent

A search path for a dependent was incorrectly specified. Either a space existed in the path or the closing brace (}) was omitted.

The syntax for a directory specification for a dependent is

{directories}dependent

where directories specifies one or more paths, each separated by a semicolon (;). No spaces are allowed.

If part or all of a search path is replaced by a macro, make sure no spaces exist in the macro expansion.


NMAKE Fatal Error U1060

unable to close file : 'filename'

NMAKE encountered an error while closing a file.

One of the following may be a cause:

  • The file is a read-only file.

  • There is a locking or sharing violation.

  • The disk is full.


NMAKE Fatal Error U1061

/F option requires a filename

The /F command-line option must be followed by either a makefile name or a dash (-), which represents standard input.


NMAKE Fatal Error U1062

missing filename with /X option

The /X command-line option requires the name of the file to which diagnostic error output should be redirected.

To use standard output, specify a dash (-) as the output filename.


NMAKE Fatal Error U1063

missing macro name before '='

A macro definition on the NMAKE command line contained an equal sign (=) without a preceding name.

This error can occur if the macro name being defined is itself a macro that expands to nothing.


NMAKE Fatal Error U1064

MAKEFILE not found and no target specified

The NMAKE command line did not specify a makefile or a target, and the current directory did not contain a file named MAKEFILE.

NMAKE requires either a makefile or a command-line target (or both). To make a makefile available to NMAKE, either specify the /F option or place a file named MAKEFILE in the current directory. NMAKE can create a command-line target by using an inference rule if a makefile is not provided.


NMAKE Fatal Error U1065

invalid option 'option'

The specified option is not a valid option for NMAKE.


NMAKE Fatal Error U1069

no match found for wildcard 'filename'

There is no file that matches the given filename, which was specified using one or more wildcards (* and ?).

A target file that is specified using a wildcard must exist on disk.


NMAKE Fatal Error U1070

cycle in macro definition 'macroname'

The given macro definition contained a macro whose definition contained the given macro. Circular macro definitions are invalid.

For example, the following macro definitions

ONE=$(TWO)
TWO=$(ONE)

cause the following error:

cycle in macro definition 'TWO'


NMAKE Fatal Error U1071

cycle in dependency tree for target 'targetname'

A circular dependency exists in the dependency tree for the given target. The given target is a dependent of one of the dependents of the given target. Circular dependencies are invalid.


NMAKE Fatal Error U1072

cycle in include files : 'filename'

The given file includes a file that eventually includes the given file. Inclusions (using the !INCLUDE preprocessing directive) cannot be circular.


NMAKE Fatal Error U1073

don't know how to make 'targetname'

The specified target does not exist, and there is no command to execute or inference rule to apply.

One of the following may be a solution:

  • Check the spelling of the target name.

  • If targetname is a pseudotarget, specify it as a target in another description block.

  • If targetname is a macro invocation, be sure it does not expand to a null string.


NMAKE Fatal Error U1076

name too long

A string exceeded one of the following limits:

  • A macro name cannot exceed 1024 characters.

  • A target name (including its path) cannot exceed 256 characters.

  • A command cannot exceed 2048 characters.


NMAKE Fatal Error U1077

'program' : return code 'value'

The given command or program called by NMAKE failed and returned the given exit code.

To suppress this error and continue the NMAKE session, use the /I option, the .IGNORE dot directive, or the dash (-) command modifier. To continue the NMAKE session for unrelated parts of the dependency tree, use the /K option.


NMAKE Fatal Error U1078

constant overflow at 'expression'

The given expression contained a constant that exceeded the range – 2,147,483,648 to 2,147,483,647. The constant appeared in one of the following situations:

  • An expression specified with a preprocessing directive

  • An error level specified with the dash (-) command modifier


NMAKE Fatal Error U1079

illegal expression : divide by zero

An expression tried to divide by zero.


NMAKE Fatal Error U1080

operator and/or operand usage illegal

The expression incorrectly used an operator or operand.

Check the allowed set of operators and their order of precedence.


NMAKE Fatal Error U1081

'filename' : program not found

NMAKE could not find the given program in order to run it.

Make sure that the program is in a directory specified in the PATH environment variable and is not misspelled.


NMAKE Fatal Error U1082

'command' : cannot execute command; out of memory

There is not enough memory to execute the given command.

One solution is to use the /N option to generate a batch file, then run the batch file instead of using NMAKE. In most cases the results will be the same.


NMAKE Fatal Error U1083

target macro 'target' expands to nothing

The given target is an invocation of a macro that has not been defined or has a null value. NMAKE cannot process a null target.


NMAKE Fatal Error U1084

cannot create temporary file 'filename'

NMAKE was unable to create the temporary file it needs when it processes the makefile.

One of the following may be a cause:

  • The file already exists with a read-only attribute.

  • There is insufficient disk space to create the file.

  • The directory specified in the TMP environment variable does not exist.


NMAKE Fatal Error U1085

cannot mix implicit and explicit rules

A target and a pair of inference-rule extensions were specified on the same line. Targets cannot be named in inference rules.


NMAKE Fatal Error U1086

inference rule cannot have dependents

The colon (:) in an inference rule must be followed by one of the following:

  • Newline character

  • Semicolon (;), which can be followed by a command

  • Number sign (#), which can be followed by a comment


NMAKE Fatal Error U1087

cannot have : and :: dependents for same target

A target cannot be specified in both a single-colon (:) and a double-colon (::) dependency.

To specify a target in multiple description blocks, use :: in each dependency line.


NMAKE Fatal Error U1088

invalid separator '::' on inference rule

An inference rule must be followed by a single colon (:).


NMAKE Fatal Error U1089

cannot have build commands for directive 'targetname'

Dot directives cannot be followed by commands. The dot directives are .IGNORE, .PRECIOUS, .SILENT, and .SUFFIXES.


NMAKE Fatal Error U1090

cannot have dependents for directive 'targetname'

Dot directives cannot be followed by dependents. The dot directives are .IGNORE, .PRECIOUS, .SILENT, and .SUFFIXES.


NMAKE Fatal Error U1092

too many names in rule

An inference rule cannot specify more than two extensions.


NMAKE Fatal Error U1093

cannot mix dot directives

Multiple dot directives cannot be specified on one line. The dot directives are .IGNORE, .PRECIOUS, .SILENT, and .SUFFIXES.


NMAKE Fatal Error U1094

syntax error : only (NO)KEEP allowed here

Something other than KEEP or NOKEEP appeared after the closing set of angle brackets (<<) specifying an inline file. Only KEEP, NOKEEP, or a newline character may follow the angle brackets. No spaces, tabs, or other characters may appear.

KEEP preserves the inline file on disk. NOKEEP deletes the file after the NMAKE session. The default is NOKEEP.


NMAKE Fatal Error U1095

expanded command line 'commandline' too long

After macro expansion, the given command line exceeded the limit on length of command lines for the operating system.

MS-DOS permits up to 128 characters on a command line.

If the command is for a program that can accept command-line input from a file, change the command and supply input from either a file on disk or an inline file. For example, LINK and LIB accept input from a response file.


NMAKE Fatal Error U1096

cannot open inline file 'filename'

NMAKE could not create the given inline file.

One of the following occurred:

  • The disk was full.

  • A file with that name exists as a read-only file.


NMAKE Fatal Error U1097

filename-parts syntax requires dependent

The current dependency does not have either an explicit dependent or an implicit dependent. Filename-parts syntax, which uses the percent (%) specifier, represents components of the first dependent of the current target.


NMAKE Fatal Error U1098

illegal filename-parts syntax in 'string'

The given string does not contain valid filename-parts syntax.


NMAKE Fatal Error U1099

stack overflow

The makefile being processed was too complex for the current stack allocation in NMAKE. NMAKE has an allocation of 0x3000 (12K).

To increase NMAKE's stack allocation, run the EXEHDR utility with a larger stack option:

EXEHDR /STACK:stacksize NMAKE.EXE

where stacksize is a number greater than the current stack allocation in NMAKE.


NMAKE Fatal Error U1100

macro 'macroname' is illegal in the context of batch rule 'rule'

NMAKE generates this error when the command block of a batch-mode rule directly or indirectly references a special file macro that is not $<.

$< is the only allowed macro for batch-mode rules.


NMAKE Error U2001

no more file handles (too many files open)

NMAKE could not find a free file handle.

One of the following may be a solution:

  • Reduce recursion in the build procedures.

  • In MS-DOS, increase the number of file handles by changing the FILES setting in CONFIG.SYS to allow a larger number of open files. FILES=50 is the recommended setting.


NMAKE Warning U4001

command file can be invoked only from command line

A command file, which is invoked by the at-sign (@) specifier, cannot contain a specification for another command file. Such nesting is not allowed. The specification was ignored.


NMAKE Warning U4002

resetting value of special macro 'macroname'

The given predefined macro was redefined.


NMAKE Warning U4004

too many rules for target 'targetname'

More than one description block was specified for the given target using single colons (:) as separators. NMAKE executed the commands in the first description block and ignored later blocks.

To specify the same target in multiple dependencies, use double colons (::) as the separator in each dependency line.


NMAKE Warning U4005

ignoring rule 'rule' (extension not in .SUFFIXES)

The given rule contained a suffix that is not specified in the .SUFFIXES list. NMAKE ignored the rule.

This warning appears only when the /P option is used.


NMAKE Warning U4006

special macro undefined : 'macroname'

The given special macro name is undefined and expands to nothing.


NMAKE Warning U4007

filename 'filename' too long; truncating to 8.3

The base name of the given file has more than eight characters, or the extension has more than three characters. NMAKE truncated the name to an eight-character base and a three-character extension.

If long filenames are supported by your file system, enclose the name in double quotation marks (").


NMAKE Warning U4008

removed target 'target'

NMAKE was interrupted while trying to build the given target, and the target file was incomplete. Because the target was not specified in the .PRECIOUS list, NMAKE deleted the file.


NMAKE Warning U4010

'target' : build failed; /K specified, continuing ...

A command in the commands block for the given target returned a nonzero exit code. The /K option told NMAKE to continue processing unrelated parts of the build and to issue an exit code 1 when the NMAKE session is finished.

If the given target is itself a dependent for another target, NMAKE issues warning U4011 after this warning.


NMAKE Warning U4011

'target' : not all dependents available; target not built

A dependent of the given target either did not exist or was out-of-date, and a command for updating the dependent returned a nonzero exit code. The /K option told NMAKE to continue processing unrelated parts of the build and to issue an exit code 1 when the NMAKE session is finished.

This warning is preceded by warning U4010 for each dependent that failed to be created or updated.


Profiler Errors PRF1005 through PRF4642

The following topics cover profiler errors PRF1005 through PRF4642.


Profiler Error PRF1005

fatal error -- common -- operating system ran out of memory

There is not enough memory to run this profiler module.


Profiler Error PRF1011

fatal error -- common -- cannot open file filename

The profiler module could not find the specified file.


Profiler Error PRF1012

fatal error -- common -- cannot read expected number of bytes from file filename

The profiler module could not read the expected number of bytes. This error is often caused by trying to profile an .EXE or .DLL file that was not linked with profiling enabled (/PROFILE linker command-line option).


Profiler Error PRF1013

fatal error -- common -- cannot write expected number of bytes to file filename

The profiler module could not write the expected number of bytes. Perhaps the disk is full or the file is read-only.


Profiler Error PRF1101

fatal error -- common -- missing option specifier

A / or - character was not followed by a command-line option specifier sequence. Check the command line.


Profiler Error PRF1102

fatal error -- common -- option: invalid option

An invalid option was found on the command line. Check the command line.


Profiler Error PRF1103

fatal error -- common -- option option requires an additional parameter.

This option was not followed by the correct number of parameters. Check the command line.


Profiler Error PRF1104

fatal error -- common -- option option requires a numeric parameter

A numeric parameter was expected for this option but was not found. Check the command line.


Profiler Error PRF1105

fatal error -- common -- option option specified more than number times

An option was specified too many times. Check the command line.


Profiler Error PRF1201

fatal error -- common -- missing filename after @

The @ character is supposed to be followed by a response filename. Check the command line.


Profiler Error PRF1202

fatal error -- common -- response files nested too deeply

Response files can be nested eight deep. Perhaps a response file calls itself recursively.


Profiler Error PRF1301

fatal error -- common -- file filename has an incorrect (old) signature

A PBI, PBO, PBT, _XE, or _LL file does not contain the correct header bytes. Perhaps the file is corrupted or was created by an old version of the profiler.


Profiler Error PRF1302

fatal error -- common -- PBI file filename has an incorrect (old) version number

A PBI file does not contain the correct version number. Perhaps the file is corrupted or was created by an old version of the profiler.


Profiler Error PRF1303

fatal error -- common -- PBT file filename has an incorrect (old) version number

A PBT file does not contain the correct version number. Perhaps the file is corrupted or was created by an old version of the profiler.


Profiler Error PRF1304

fatal error -- common -- PBT or PBO file filename conflicts with current profiling state

There was an attempt to merge a PBT or a PBO file into another PBT file with a different profiling mode selected.


Profiler Error PRF1306

fatal error -- common -- PBT or PBO file filename is not derived from same PBI file

The PBT, PBO, and PBI files are not properly synchronized. Run PREP Phase I again.


Profiler Error PRF1307

fatal error -- common -- CPU type of module module is different from initial one

CPU types for different modules don't match. All modules must be compiled for the same CPU type.


Profiler Error PRF1401

fatal error -- common -- filename: not a portable executable file

Function profiling only: The specified executable file is not a standard executable file for Windows NT. Perhaps it is a 16-bit executable for Windows 3.x.


Profiler Error PRF1421

fatal error -- PREP I -- no input specified

There were no input modules specified for PREP Phase I. Check the command line.


Profiler Error PRF1422

fatal error -- PREP I -- syntax error in /EXC or /INC specification: specification

The /EXC and /INC options require function names or filenames. This specification could not be decoded. Check the command line.


Profiler Error PRF1423

fatal error -- PREP I -- number of modules exceeds number

The maximum number of modules has been exceeded. Restructure the merge procedure to include more stages.


Profiler Error PRF1424

fatal error -- PREP I -- Debugging information in filename is not the right format for profiling, relink with /PROFILE

Could not use debuggine information stored in the Program Database. Debug information, to be used, must be stored in the executable in old-style format. Relink with the /PROFILE option to do this.


Profiler Error PRF1425

fatal error -- PREP I -- filename: invalid runtime relocation, try relink

The profiler found bad relocation information in the program to be profiled. This is usually caused by using an obsolete version of the linker. Relink your code with the new profiler and run PREP again.


Profiler Error PRF1426

A fixed image executable cannot be profiled, relink file without the /fixed switch


Profiler Error PRF1427

Executable image too large to profile - try breaking it down into smaller DLLs.

The executable cannot be profile at its present size.


Profiler Error PRF1441

fatal error -- PROFILE -- filename: not a valid Win32s executable file

Win32s only. The Win32s extension could not load this file. Perhaps the file is corrupted, has not been prepared for profiling, or is not a graphical user interface application. If the file were a 16-bit executable, error message 1401 would be issued.


Profiler Error PRF1442

fatal error -- PROFILE -- timestamp of executable has changed since PREP was run

The PBI file was created from an older EXE file. This means that the processed executable file has changed since it was originally created by PREP Phase I. Run PREP Phase I again.


Profiler Error PRF1443

fatal error -- PROFILE -- cannot run program filename

The profiler could not load the EXE file. Check that the original EXE file does run under Windows NT.


Profiler Error PRF1444

this version of Windows does not support this manner of profiling

The function timing (/ft) option is not supported for this version of Windows.


Profiler Error PRF1445

Line count and line coverage are not supported on Win32S.

The Win32S version of the profiler does not support line count or line coverage profiling.


Profiler Error PRF1461

fatal error -- PREP II -- no PBT output file specified

Neither the /OT nor /M option was specified. Check the command line.


Profiler Error PRF1462

fatal error -- PREP II -- no PBT input file specified

Neither the /IT nor /M option was specified. Check the command line.


Profiler Error PRF1463

fatal error -- PREP II -- module: different clock/sampling frequency

The sampling frequency for this module is different from that of other modules that were profiled. Rerun PROFILE again for all modules, using the same sampling frequency.


Profiler Error PRF1465

fatal error -- PREP II -- CPU type in PBT or PBO file filename conflicts with current one

Occurs only during PREP merging. The CPU type does not match the CPU type used to generate the incoming PBT or PBO files. All profiler steps must be run on the same type of computer.


Profiler Error PRF1481

fatal error -- PLIST -- option inconsistent with sorting type

The options for PLIST depend on the kind of profiling being done. This error occurs, for example, when the Sort By Name option is specified for a line profiling run.


Profiler Error PRF1482

fatal error -- PREP or PROFILE -- abnormal termination in PREP or PROFILE detected, PLIST cannot continue

The files output by PREP or PROFILE were not valid because one of these utilities did not complete its task. This error is usually caused by an error during the execution of PREP or PROFILE, such as a missing .MAP file.


Profiler Error PRF1504

fatal error -- common -- illegal fixup address in mapfile filename

The mapfile lists all link-time fixups (including all the function call sites). This error indicates that one of the fixups was illegal, perhaps because the mapfile was not generated by the same link as the corresponding EXE (or DLL). This error is often preceded by the warning (PRF4528) about the EXE and mapfile timestamps being out of sync.


Profiler Error PRF1521

fatal error -- PREP I -- no functions were marked for profiling in module module

Function profiling only: at least one function must be included for profiling in each module. Check the /INC, /EXC, and /EXCALL options on the command line.


Profiler Error PRF1522

fatal error -- PREP I -- more than one function matched entry specification: funcname1 and funcname2

Function profiling only: there were two or more functions with matching names. Perhaps these are C++ overloaded functions. Use decorated names to specify the functions.


Profiler Error PRF1523

fatal error -- PREP I -- filename is not profiled, and can not import modified version version

For function-level profiles, PREP uses modified EXEs and DLLs, with modified names with extensions _XE and _LL. If any modules listed in the import table of a profiled module refer to another profiled module, but the imported module is itself not being profiled, then the import table of that imported module cannot be changed, and this error occurs. The solution is to include the offending module in the profile.


Profiler Error PRF1524

fatal error -- PREP I -- Debugging info in filename is not the right format for profiling, relink with /PROFILE

You must link executable files with profiling enabled (the /PROFILE linker option) to profile them. Change your linker options, rebuild, and re-run PREP.


Profiler Error PRF1542

fatal error -- PROFILE -- cannot set or delete environment variable var

Function profiling only: The specified environment variable was unavailable.


Profiler Error PRF1543

fatal error -- PROFILE -- NtQueryIntervalProfile: NT internal error number occurred

A Windows NT error was detected.


Profiler Error PRF1544

fatal error -- PROFILE -- NtSetIntervalProfile: NT internal error number occurred

A Windows NT error was detected.


Profiler Error PRF1545

fatal error -- PROFILE -- function sampling is no longer supported

Function sampling is not supported in this version of Visual C++. Use function timing to get more accurate results.


Profiler Error PRF1621

fatal error -- PREP I -- no debugging information in file filename

Line profiling only: debugging information must be included in the executable file. Run the compiler and linker again with the debugging options set.


Profiler Error PRF1622

fatal error -- PREP I -- no source lines marked for profiling in module module

Line profiling only: at least one line must be included for profiling in each module. Check the /INC, /EXC, and /EXCALL options on the command line.


Profiler Error PRF1641

fatal error -- PROFILE -- user-defined breakpoint found at address

Line profiling only: No breakpoints may be set in the executable modules being profiled. These are not breakpoints set by the debugger but rather embedded INT 3 instructions. This error is only fatal if the INT 3 instruction is encountered during the execution of your program.


Profiler Error PRF1642

fatal error -- PROFILE -- unexpected single-step exception occurred at address

Line profiling only: There was a problem with the executable file. Try relinking and rerunning PREP Phase I.


Profiler Error PRF1643

fatal error -- PROFILE -- an access violation occurred at address

Line profiling only: There was a problem with the executable file. Try relinking and rerunning PREP Phase I. Check the EXE file with the debugger.


Profiler Error PRF2541

error -- PROFILE -- cannot start sampler

Perhaps the executable program is too large.


Profiler Error PRF2542

error -- PROFILE -- cannot stop sampler

Perhaps the executable program is too large.


Profiler Error PRF4101

warning -- common -- option option overrides an earlier option

Two or more mutually exclusive switches were specified, or the same switch was specified more than once. The last switch takes precedence.


Profiler Error PRF4106

warning -- common -- function/source/object/lib name was never matched

The program element was not found. Make sure the name was spelled or decorated correctly.


Profiler Error PRF4107

warning -- common -- /SF option not valid for line-level or sample profiles

The start function option should be used only with function timing, function counting, or function coverage profiling.


Profiler Error PRF4111

warning -- common -- no error file (/E) specified for /A option

The /A option cannot be used without the /E option. The /A option is ignored and the error output sent to stdout.


Profiler Error PRF4421

warning -- PREP I -- an offset duplication was detected

There appears to be a problem with the (codeview) line number debug information. Perhaps there is an aliasing problem.


Profiler Error PRF4422

warning -- PREP I -- filename imports unknown module module

PREP searches for imported modules (mostly DLLs) in the following sequence:

  • Directory PREP itself lives in

  • Current directory

  • Windows directories

  • Directories on the path

Because the current directory depends on the profiler rather than on the profiled program, all modules might not be found. In most cases, this warning is not serious. However, if profiling leads to a GP fault (or to incorrect behavior), it might be necessary to include the "unknown module" in the profile.


Profiler Error PRF4423

warning -- PREP I -- filename: ignoring unknown runtime relocation type, verify linker version

(MIPS Specific) The profiler found bad relocation information in the program to be profiled. This is usually caused by using an obsolete version of the linker. Relink your code with the new profiler, and run PREP again.


Profiler Error PRF4481

warning -- PLIST -- clock frequency is zero

The clock frequency field in the PBT file has not been filled in yet, perhaps because the user has not done a profile yet, or has not merged his PBO file into his PBT file. Running PREP /M should fix the problem.


Profiler Error PRF4521

warning -- PREP I -- INIT environment variable not defined

The INIT environment variable should point to the directory that contains TOOLS.INI. Set the INIT environment variable to the directory containing your TOOLS.INI and rerun PREP.


Profiler Error PRF4522

warning -- PREP I -- 'publics' section not found in mapfile filename

The mapfile is corrupt.


Profiler Error PRF4523

warning -- PREP I -- 'static symbols' section not found in mapfile filename

The mapfile is corrupt.


Profiler Error PRF4524

warning -- PREP I -- entry function function not found

PREP could not find the specified start function (entry function) in the mapfile (see /SF switch). Perhaps the function name is misspelled.


Profiler Error PRF4525

warning -- PREP I -- cannot profile function function in file filename

A special function such as setjmp was specified.


Profiler Error PRF4526

warning -- PREP I -- module module already includes profiler DLL filename

The specified EXE or DLL already imports from PROFILER.DLL. The EXE (or DLL) may have been modified by PREP using the /OM switch and then renamed (from app._XE to app.EXE) before PREP was run again. Make sure that the module (EXE or DLL) specified is the original module and a module modified by PREP.


Profiler Error PRF4527

warning -- PREP I -- preferred load address not found in mapfile filename; assumed address

Current versions of the linker list the preferred load address (that is, when the EXE gets loaded at this address none of the run-time relocation addresses need to be fixed up). PREP needs this information. Somehow this information was missing from the mapfile. If the latest linker was used, the mapfile was probably edited. Regenerate the mapfile, retaining the line that states the preferred load address.


Profiler Error PRF4528

warning -- PREP I -- timestamps of mapfile filename and executable file do not match

The mapfile is not properly synchronized with the executable file. Relink and run PREP again.


Profiler Error PRF4541

warning -- PROFILE -- module not found in PBI file filename

An attempt was made to profile a program, but the EXE was not modified by PREP. This warning occurs while selectively profiling a DLL that is called by the EXE.


Profiler Error PRF4621

warning -- PREP I -- line number duplicated in file filename

There is a problem with the line number debug information. The same line number was identified with two different addresses. This is generally not serious.


Profiler Error PRF4641

warning -- PROFILE -- ReadProcessMemory: internal NT error number occurred

An internal error occurred. The profiler results may be meaningless.


Profiler Error PRF4642

warning -- PROFILE -- WriteProcessMemory: internal NT error number occurred

An internal error occurred. The profiler results may be meaningless.


C Run-Time Errors R6002 through R6025

The following topics cover C run-time errors R6002 through R6025.


C Run-Time Error R6002

floating-point support not loaded

The program needs the floating-point library, but the library was not linked to the program.

One of the following may have occurred:

  • The program was compiled or linked with an option (such as /FPi87) that required a coprocessor, but the program was run on a machine that did not have a coprocessor installed.

  • A format string for a printf or scanf function contained a floating-point format specification, and the program did not contain any floating-point values or variables.

  • The compiler minimizes a program's size by loading floating-point support only when necessary. The compiler cannot detect floating-point format specifications in format strings, so it does not load the necessary floating-point routines.

  • Use a floating-point argument to correspond to the floating-point format specification, or perform a floating-point assignment elsewhere in the program. This causes floating-point support to be loaded.

  • In a mixed-language program, a C library was specified before a FORTRAN library when the program was linked. Relink and specify the C library last.


C Run-Time Error R6005

not enough memory on _exec

Not enough memory was available to load the process being spawned.

This error occurs when a child process that was spawned by one of the _exec library routines fails and the operating system cannot return control to the parent process.


C Run-Time Error R6006

invalid format on _exec

The file to be executed by one of the _exec functions was not in the correct format for an executable file.

This error occurs when a child process that was spawned by one of the _exec library routines fails and the operating system cannot return control to the parent process.


C Run-Time Error R6007

invalid environment on _exec

During a call to an _exec function, the operating system found that the child process was given an invalid environment block.

This error occurs when a child process that was spawned by one of the _exec library routines fails and the operating system cannot return control to the parent process.


C Run-Time Error R6008

not enough space for arguments

There was enough memory to load the program but not enough memory to create the argv array.

One of the following may be a solution:

  • Increase the amount of memory available to the program.

  • Reduce the number and size of command-line arguments.

  • Reduce the environment size by removing unnecessary variables.


C Run-Time Error R6009

not enough space for environment

There was enough memory to load the program but not enough memory to create the envp array.

One of the following may be a solution:

  • Increase the amount of memory available to the program.

  • Reduce the number and size of command-line arguments.

  • Reduce the environment size by removing unnecessary variables.

If your program uses the compact, large, or huge memory model, this error may be avoided by using LINK's /CPARM:1 command-line option. This option causes unused near heap space to be allocated to the far heap.


C Run-Time Error R6016

not enough space for thread data

The program did not receive enough memory from the operating system to complete a _beginthread call.

When a new thread is started, the library must create an internal database for the thread. If the database cannot be expanded with memory provided by the operating system, the thread will not begin and the calling process will stop.


C Run-Time Error R6017

unexpected multithread lock error

The process received an unexpected error while trying to access a C run-time multithread lock on a system resource.

This error usually occurs if the process inadvertently alters the run-time heap data. However, it can also be caused by an internal error in the run-time or operating-system code.


C Run-Time Error R6018

unexpected heap error

The program encountered an unexpected error while performing a memory-management operation.

This error usually occurs if the program inadvertently alters the run-time heap data. However, it can also be caused by an internal error in the run-time or operating-system code.

If your compiler provides a library containing _heapchk and _heapwalk, you can use these functions to diagnose this error.


C Run-Time Error R6019

unable to open console device

The program called a console function declared in CONIO.H, but the operating system did not grant access to the console.


C Run-Time Error R6021

no main procedure

The program does not have a procedure called main.

Make sure that all object and library modules have been linked into the executable.


C Run-Time Error R6024

not enough space for _onexit/atexit table

There was no memory available for the _onexit or atexit function. This error is caused by a low-memory condition.


C Run-Time Error R6025

pure virtual function call

No object has been instantiated to handle the pure virtual function call.

This error is caused by calling a virtual function in an abstract base class through a pointer which is created by a cast to the type of the derived class, but is actually a pointer to the base class. This can occur when casting from a void* to a pointer to a class when the void* was created during the construction of the base class.


Resource Compiler Errors RC1000 through RC4413

The following topics cover resource compiler error RC1000 through warning RC4413.


Resource Compiler Fatal Error RC1000

UNKNOWN FATAL ERROR

Note the circumstances of the error, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Resource Compiler Fatal Error RC1002

out of heap space

The Resource Compiler ran out of storage for items that it stores in its heap. One of the following may be a solution:

  • Increase the Windows swap file space. For more information about increasing the swap-file space refer to the Microsoft Windows User's Guide.

  • Split the current file into two or more files and compile them separately.

  • Remove other programs or drivers running in the system, which could be consuming significant amounts of memory.


Resource Compiler Fatal Error RC1003

error count exceeds number; stopping compilation

The number of errors was too great to continue compilation. Fix some errors and recompile.


Resource Compiler Fatal Error RC1004

unexpected end of file found

This error can be caused by omitting the linefeed and carriage return characters on the last line of a text file.


Resource Compiler Fatal Error RC1005

file not found: filename

The file specified in the RC command line was not found. Check to see whether the file has been moved to another directory and whether the filename or path is typed correctly.

Files are searched for using the INCLUDE environment variable or the Visual C++ Directories setting.


Resource Compiler Fatal Error RC1007

unrecognized option 'option' in 'filename'

The specified option is not valid.


Resource Compiler Fatal Error RC1008

no input file specified

One or more source files must be specified on the Resource Compiler command line.


Resource Compiler Fatal Error RC1009

compiler limit : macros too deeply nested 'macro'

The Resource Compiler limit for macro nesting was exceeded. Revise the specified source file to decrease the nesting depth of its macros.


Resource Compiler Fatal Error RC1010

no output file specified

The Resource Compiler command line did not specify a filename for the compiled resource file.


Resource Compiler Fatal Error RC1011

compiler limit : 'identifier' : macro definition too big

The macro definition was longer than allowed.

Try to split the definition into shorter definitions.


Resource Compiler Fatal Error RC1012

unmatched parenthesis : missing 'character'

The parentheses in a preprocessor directive were not matched. The missing character is either a left or right parenthesis.


Resource Compiler Fatal Error RC1013

mismatched parentheses

Make sure that every open parenthesis has a matching closing parenthesis.


Resource Compiler Fatal Error RC1014

too many include files : depth = 'level'

The nesting depth of #include directives was too great.

Open files can be included by the use of nested directives. The source file containing the directive is counted as one of the files.


Resource Compiler Fatal Error RC1015

cannot open include file 'filename'

The given include file either did not exist, could not be opened, or was not found.

Make sure that the environment settings are valid and that the correct path for the file is specified. Ensure that sufficient file handles are available to the Resource Compiler. If the file is on a network drive, make sure that you have permissions to open the file.


Resource Compiler Fatal Error RC1016

#if[n]def expected an identifier

The #ifdef or #ifndef conditional compilation directive was not supplied with an identifier to evaluate.

An identifier must be specified with the #ifdef and #ifndef directives.


Resource Compiler Fatal Error RC1017

invalid integer constant expression

The expression in an #if directive either did not exist or did not evaluate to a constant.


Resource Compiler Fatal Error RC1018

unexpected '#elif'

The #elif directive did not appear within an #if, #ifdef, or #ifndef construct.

Make sure that there is an #if, #ifdef, or #ifndef statement in effect before this statement.


Resource Compiler Fatal Error RC1019

unexpected '#else'

The #else directive did not appear within an #if, #ifdef, or #ifndef construct.

Make sure that there is an #if, #ifdef, or #ifndef statement in effect before this statement.


Resource Compiler Fatal Error RC1020

unexpected '#endif'

An #endif directive appeared without a matching #if, #ifdef, or #ifndef directive.

Make sure that there is a matching #endif for each #if, #ifdef, and #ifndef statement.


Resource Compiler Fatal Error RC1021

invalid preprocessor command 'string'

The characters following the number sign (#) did not form a valid preprocessor directive.

The number sign cannot be used as the first character in an identifier.


Resource Compiler Fatal Error RC1022

expected '#endif'

An #if, #ifdef, or #ifndef directive was not terminated with an #endif directive.

Make sure that there is an #if, #ifdef, or #ifndef statement in effect before this statement.


Resource Compiler Fatal Error RC1023

cannot open source file 'filename'

The specified file either did not exist, could not be opened, or was not found.

Make sure that the environment settings are valid and that the correct path for the file is specified.

If this error appears without an error message, the Resource Compiler has run out of file handles.


Resource Compiler Fatal Error RC1047

"too many option options, 'string'"

The given option was specified too many times. The given string is the argument to the option that caused the error.


Resource Compiler Fatal Error RC1048

unknown option 'character' in 'option'

The given character was not a valid letter for the option.


Resource Compiler Fatal Error RC1049

invalid numerical argument 'string'

The Resource Compiler expected a numerical argument but received the given string.

This error may be caused by giving a hexadecimal number without the necessary \x prefix or by a misformed floating-point number.


Resource Compiler Fatal Error RC1052

compiler limit : #if or #ifdef blocks nested too deeply

The program exceeded the maximum allowable nesting levels for #if and #ifdef directives.

This error can be caused by include files that use these preprocessor directives.


Resource Compiler Fatal Error RC1067

compiler limit : identifier overflowed internal buffer

An internal compiler limit was exceeded.


Resource Compiler Fatal Error RC1101

no resource binary filename specified

The Rename Output (/fo) option was specified, but was not followed by filename.

The following syntax must be used with the /fo option:

RC /fo outfilename infilename.rc


Resource Compiler Fatal Error RC1102

internal error : too many arguments to RCPP

Too many arguments were passed to the Resource Compiler preprocessor. Reduce the number of symbols defined with the Define Symbols (/d) option by defining them in your source. This error can also be caused by specifying too many include file search paths using the Include Search Path option (/i).


Resource Compiler Fatal Error RC1103

invalid switch, option

The specified option is not a valid Resource Compiler option.


Resource Compiler Fatal Error RC1105

invalid switch, option: too many /d switches

Too many symbols were defined using the Define Symbols (/d) option. Define some symbols in your source and recompile.


Resource Compiler Fatal Error RC1106

invalid switch: option

The specified option is not a valid Resource Compiler option. The following options are valid:

/r

Emit .RES file

/v

Verbose (print progress messages)

/d

Define a symbol

/fo

Rename .RES file

/l

Default language ID in hex

/I Add a path for INCLUDE searches

/x

Ignore INCLUDE environment variable

/c

Define a code page used by NLS Conversion


Resource Compiler Fatal Error RC1107

invalid usage; use RC /? for Help

An invalid Resource Compiler option was specified. Valid options are one of the following: /r, /v, /d, /fo, /l, /i, /x, or /c:


Resource Compiler Fatal Error RC1109

error creating resource-name

Could not create specified .RES file. Make sure it is not being created on a read-only drive. Use the /V option to find out whether the file is being created.


Resource Compiler Fatal Error RC1110

could not open filename

RC could not open the specified resource script file. Make sure that the file exists.


Resource Compiler Fatal Error RC1116

RC terminating after preprocessor errors

The Resource Compiler halted due to other errors. Fix the other errors and recompile.


Resource Compiler Fatal Error RC1120

out of memory, needed number bytes

The Resource Compiler ran out of storage for items that it stores in its heap. Usually this is the result of having too many symbols.

One of the following may be a solution:

  • Increase the Windows swap file space. For more information about increasing the swap-file space refer to the Microsoft Windows User's Guide.

  • Eliminate unnecessary include files, especially unneeded #defines and function prototypes.

  • Split the current file into two or more files and compile them separately.

  • Remove other programs or drivers running in the system, which could be consuming significant amounts of memory.


Resource Compiler Fatal Error RC1121

I/O error reading file

The Resource Compiler was not able to read a file. Check that the drive containing the file is available and that the file is valid.


Resource Compiler Fatal Error RC1122

I/O error writing file

The Resource Compiler could not write to a file.

This error may be caused by insufficient disk space. You must have free space equivalent to about twice the size of the executable file you are creating.

Other possible reasons for this error are:

  • Writing to a read-only volume

  • Writing to a bad sector

  • A sharing violation


Resource Compiler Fatal Error RC1123

I/O error seeking in file

The compiler was unable to complete an I/O operation.


Resource Compiler Fatal Error RC1201

invalid switch - missing include path after /i

The Specify Include Path (/i) option was specified, but was not followed by a path.


Resource Compiler Fatal Error RC1202

invalid switch - missing default language ID after /l

The Specify Default Language (/l) option was specified, but was not followed by a hexadecimal language ID.


Resource Compiler Fatal Error RC1203

invalid hexadecimal default language ID specified.

The Specify Default Language (/l) option was specified, but was followed by an invalid hexadecimal language ID. See Language and Country Strings in the Run-Time Library Reference for a list of valid language IDs.


Resource Compiler Fatal Error RC1204

Invalid switch - missing code page after /c

The Specify Code Page (/c) option was specified, but it was not followed by a code page.


Resource Compiler Fatal Error RC1205

invalid code page

The Specify Code Page (/c) option was specified, but was followed by an invalid code page. See Code Pages in the Run-Time Library Reference for more information.


Resource Compiler Fatal Error RC1206

specified code page at cmd line does not exist in registry

The Specify Code Page (/c) option was specified, but was followed by a code page whose location is not specified in the registry. Run SETUP to install the specified code page.


Resource Compiler Fatal Error RC1207

default code page is invalid

The code page specified by the RCCODEPAGE environment variable is not valid. See Code Pages in the Run-Time Library Reference for more information.


Resource Compiler Fatal Error RC1208

input file has .RES extension

The .RES extension is used for Resource Compiler output. The .RC extension should be used for Resource Compiler scripts.


Resource Compiler Error RC2001

newline in constant

A string constant was continued on a second line without either a backslash (\) or closing and opening double quotation marks (").

To break a string constant that is on two lines in the source file, do one of the following:

  • End the first line with the line-continuation character, a backslash.

  • Close the string on the first line with a double quotation mark and open the string on the next line with another quotation mark.

It is not sufficient to end the first line with \n, the escape sequence for embedding a newline character in a string constant.


Resource Compiler Error RC2003

expected 'defined id'

An identifier was expected after the specified preprocessing keyword.


Resource Compiler Error RC2004

expected 'defined(id)'

An identifier was expected after the left parenthesis following the specified preprocessing keyword.


Resource Compiler Error RC2005

#line expected a line number, found 'token'

A #line directive lacked the required line-number specification.


Resource Compiler Error RC2006

#include expected a filename, found 'token'

An #include directive lacked the required filename specification.


Resource Compiler Error RC2007

#define syntax

An identifier was expected following #define in a preprocessing directive.


Resource Compiler Error RC2008

'character' : unexpected in macro definition

The given character was found immediately following the name of the macro.


Resource Compiler Error RC2009

reuse of macro formal 'identifier'

The given identifier was used more than once in the formal parameter list of a macro definition.


Resource Compiler Error RC2010

'character' : unexpected in formal list

The given character was used incorrectly in the formal parameter list of a macro definition.


Resource Compiler Error RC2012

missing name following '<'

An #include directive lacked the required filename specification.


Resource Compiler Error RC2013

missing '>'

The closing angle bracket (>) was missing from an #include directive.


Resource Compiler Error RC2014

preprocessor command must start as first non-whitespace

Non-white-space characters appeared before the number sign (#) of a preprocessor directive on the same line.


Resource Compiler Error RC2015

too many chars in constant

A character constant contained more than two characters.

Character constants are limited to one character (standard character constants) or two characters (long character constants).

Note that an escape sequence (for example, \t for tab) is converted to a single character.


Resource Compiler Error RC2016

no closing single quote

A newline character was found before the closing single quotation mark of a character constant.


Resource Compiler Error RC2017

illegal escape sequence

An escape sequence appeared where one was not expected.

An escape sequence — a backslash ( \ ) followed by a number or letter — may occur only in a character or string constant.


Resource Compiler Error RC2018

unknown character 'hexnumber'

The ASCII character corresponding to the given hexadecimal number appeared in the source file but is an illegal character.

One possible cause of this error is corruption of the source file.


Resource Compiler Error RC2019

expected preprocessor directive, found 'character'

The given character followed a number sign (#), but it was not the first letter of a preprocessor directive.


Resource Compiler Error RC2020

illegal digit number for base radix

The specified digit is not a valid digit for the base specified by radix. Either the digit or the radix could be incorrect.

Octal digits must be numbers from 0 to 7, and hexadecimal digits must be numbers from 0 to 9 or letters from A through E.


Resource Compiler Error RC2021

expected exponent value, not 'character'

The given character was used as the exponent of a floating-point constant but was not a valid number.


Resource Compiler Error RC2022

'number' : too big for character

The octal number following a backslash (\) in a character or string constant was too large to be represented as a character.


Resource Compiler Error RC2101

Invalid directive in preprocessed RC file

The RC file contains a #pragma directive.

Use the #ifndef preprocessor directive with the RC_INVOKED constant that the Resource Compiler defines when it processes an include file. Place the #pragma directive inside a block of code that is not processed when the RC_INVOKED constant is defined. Code in the block is processed only by the C/C++ compiler and not by the Resource Compiler. The following sample code demonstrates this technique:

#ifndef RC_INVOKED
#pragma pack(2)  // C/C++ only, ignored by Resource Compiler
#endif

The #pragma preprocessor directive has no meaning in an .RC file. The #include preprocessor directive is used frequently in an .RC file to include a header file (either a project-based custom header file or a standard header file provided by Microsoft with one of its products). Some of these include files contain the #pragma directive. Because a header file can include one or more other header files, the file that contains the offending #pragma directive may not be immediately obvious.

The #ifndef RC_INVOKED technique can control including header files in project-based header files.


Resource Compiler Error RC2102

string literal too long

An RCDATA string exceeded the maximum allowable length.


Resource Compiler Error RC2103

unexpected end of file in string literal

An end of file was found before the end of a string. The string is probably missing a closing double quotation mark (").


Resource Compiler Error RC2104

undefined keyword or key name: key

The specified keyword or key name was not defined.

If you encounter the following error message:

undefined keyword or key name: MFT_STRING

open MCL\MFC\Include\AfxRes.h and add the following include directive:

#include <winresrc.h>


Resource Compiler Error RC2105

BEGIN expected in string table

The BEGIN keyword must immediately follow the ACCELERATORS keyword.


Resource Compiler Error RC2106

BEGIN expected in accelerator table

The BEGIN keyword must immediately follow the ACCELERATORS keyword.


Resource Compiler Error RC2107

expected numeric command value

RC was expecting a numeric idvalue field in the ACCELERATORS statement. Make sure that you have used a #define constant to specify the value and that the constant is spelled correctly.


Resource Compiler Error RC2108

unbalanced parentheses

An open parenthesis was not matched with a closing parenthesis.


Resource Compiler Error RC2109

expected numerical dialog constant

A DIALOG statement requires integer values for the x, y, width, and height fields. Make sure these values are included after the DIALOG keyword and that they are not negative.


Resource Compiler Error RC2110

expected numerical dialog constant

A DIALOG statement requires integer values for the x, y, width, and height fields. Make sure these values are included after the DIALOG keyword and that they are not negative.


Resource Compiler Error RC2111

invalid control type

Each CONTROL statement in a DIALOG statement must be one of the following: 3STATE, AUTO3, AUTOCHECK, AUTORADIO, BEDIT, CHECKBOX, COMBOBOX, CONTROL, CTEXT, DEFPUSHBUTTON, EDITTEXT, GROUPBOX, HEDIT, ICON, IEDIT, LISTBOX, LTEXT, PUSHBOX, PUSHBUTTON, RADIOBUTTON, RTEXT, SCROLLBAR, USERBUTTON.

Make sure these CONTROL statements are spelled correctly.


Resource Compiler Error RC2112

BEGIN expected in dialog

The BEGIN keyword must immediately follow the DIALOG keyword.


Resource Compiler Error RC2113

END expected in dialog

The END keyword must occur at the end of a DIALOG statement. Make sure there are no open quotes left from the preceding statement.


Resource Compiler Error RC2114

expected control class name

The class field of a CONTROL statement in the DIALOG statement must be one of the following types: BUTTON, COMBOBOX, EDIT, LISTBOX, SCROLLBAR, STATIC, or user-defined. Make sure the class is spelled correctly.


Resource Compiler Error RC2115

text string or ordinal expected in control

The text field of a CONTROL statement in the DIALOG statement must be either a text string or an ordinal reference to the type of control is expected. If using an ordinal, make sure that you have a #define statement for the control.


Resource Compiler Error RC2116

expecting number for ID

Expecting a number for the id field of a control statement in the DIALOG statement. Make sure you have a number or #define statement for the control ID.


Resource Compiler Error RC2117

expected numeric point size

The pointsize field of the FONT option in the DIALOG statement must be an integer point size value.


Resource Compiler Error RC2118

expected font face name

The typeface field of the FONT option in the DIALOG statement must be an ASCII character string enclosed in double quotation marks. This field specifies the name of a font.


Resource Compiler Error RC2119

expecting quoted string in dialog title

The captiontext field of the CAPTION option in the DIALOG statement must be an ASCII character string enclosed in double quotation marks.


Resource Compiler Error RC2120

expecting quoted string in dialog class

The class field of the CLASS option in the DIALOG statement must be an integer or a string, enclosed in double quotation marks.


Resource Compiler Error RC2121

BEGIN expected in menu

The BEGIN keyword must immediately follow the MENU keyword.


Resource Compiler Error RC2122

unknown menu subtype

The item-definition field of the MENU statement can contain only MENUITEM and POPUP statements.


Resource Compiler Error RC2123

END expected in menu

The END keyword must come at the end of a MENU statement. Make sure you do not have any open quotation marks or a mismatched pair of BEGIN and END statements.


Resource Compiler Error RC2124

empty menus not allowed

An END keyword appears before any menu items are defined in the MENU statement. Empty menus are not permitted by the Resource Compiler. Make sure you do not have any open quotation marks within the MENU statement.


Resource Compiler Error RC2125

expected ID value for menuitem

The MENU statement must contain a menuID field, which specifies the name or number that identifies the menu resource.


Resource Compiler Error RC2126

expected menu string

Each MENUITEM and POPUP statement must contain a text field, which is a string enclosed in double quotation marks that specifies the name of the menu item or pop-up menu. A MENUITEM SEPARATOR statement requires no quoted string.


Resource Compiler Error RC2127

version WORDs separated by commas expected

Version numbers in a version resource should be of type WORD, and separated by commas.


Resource Compiler Error RC2128

DWORD expected

A valid version number was not found. It must be a DWORD type.


Resource Compiler Error RC2129

BEGIN expected in VERSIONINFO resource

The BEGIN keyword must immediately follow the VERSIONINFO keyword.


Resource Compiler Error RC2130

#line expected a string containing the file name, found 'token'

A #line directive was missing a required filename.


Resource Compiler Error RC2131

expecting quoted string for key

The field for this statement must be a character string enclosed in double quotation marks.


Resource Compiler Error RC2132

expected VALUE, BLOCK, or, END keyword

A block in a VERSION resource doesn’t end properly, or a new block doesn’t begin properly. This results in a VERSION statement that is not a valid block.


Resource Compiler Error RC2133

unexpected value in value data

The raw-data values in the RCDATA statement must be integers or strings, each separated by a comma. Make sure you did not leave out a comma or leave out a quotation mark around a string.


Resource Compiler Error RC2134

BEGIN expected in RCDATA

The BEGIN keyword must immediately follow the RCDATA keyword.


Resource Compiler Error RC2135

file not found: filename

The file specified in the RC command line was not found. Check to see whether the file has been moved to another directory and whether the filename or path is typed correctly.

Files are searched for using the INCLUDE environment variable or the Visual C++ INCLUDE setting.


Resource Compiler Error RC2136

missing '=' in EXSTYLE=<flags>

An equal sign (=) was missing from an EXSTYLE (Extended Style Flags) statement. When the EXSTYLE is embedded in the DIALOG or MENU statement it must have the following form:

EXSTYLE=FLAGS


Resource Compiler Error RC2137

empty character constant

A pair of single quotes was found with no character specified between them.


Resource Compiler Error RC2138

unmatched close comment '/*'

An open comment sequence (/*) was not matched with a close comment sequence (*/) This error can be caused by nesting comments.


Resource Compiler Error RC2139

VERSION not a number

A VERSION resource must be a number.


Resource Compiler Error RC2140

CHARACTERISTICS not a number

A CHARACTERISTICS resource must be a number.


Resource Compiler Error RC2141

invalid type

A different type was expected.


Resource Compiler Error RC2142

ellipsis requires three periods

An incorrect number of periods (.) was used in an ellipsis.


Resource Compiler Error RC2143

font names must be ordinals

The pointsize field in the FONT statement must be an integer, not a string.


Resource Compiler Error RC2144

PRIMARY LANGUAGE ID not a number

The PRIMARY LANGUAGE ID must be a hexadecimal language ID. See Language and Country Strings in the Run-Time Library Reference for a list of valid Language IDs.


Resource Compiler Error RC2145

PRIMARY LANGUAGE ID too large

The PRIMARY LANGUAGE ID must be a valid hexadecimal language ID. See Language and Country Strings in the Run-Time Library Reference for a list of valid Language IDs.


Resource Compiler Error RC2146

missing COMMA in LANGUAGE statement

The comma separating the primary language and secondary language is missing.

The LANGUAGE statement must use the following syntax:

LANGUAGE primary_language_ID,secondary_language_ID


Resource Compiler Error RC2147

SUBLANGUAGE ID not a number

The SUBLANGUAGE ID value must be a number.

The LANGUAGE statement must use the following syntax:

LANGUAGE primary_language_ID,secondary_language_ID

Valid SUBLANGUAGE IDs are defined as SUBLANG_ constants in the WINNT.H file.


Resource Compiler Error RC2148

SUBLANGUAGE ID too large

The SUBLANGUAGE ID value was out of range.

The LANGUAGE statement must use the following syntax:

LANGUAGE primary_language_ID,secondary_language_ID

Valid SUBLANGUAGE IDs are defined as SUBLANG_ constants in the WINNT.H file.


Resource Compiler Error RC2149

expected numeric constant in string table

A numeric constant, defined in a #define statement, must immediately follow the BEGIN keyword in a STRINGTABLE statement.


Resource Compiler Error RC2150

expected string in STRINGTABLE

A string is expected after each stringid value in a STRINGTABLE statement.


Resource Compiler Error RC2151

cannot re-use string constants

You are using the same value twice in a STRINGTABLE statement. Make sure you are not mixing overlapping decimal and hexadecimal values.

Each ID in a STRINGTABLE must be unique. For maximum efficiency use contiguous constants that start on a multiple of 16.


Resource Compiler Error RC2152

invalid control character

A control character in the ACCELERATORS statement is invalid. A valid control character consists of one letter (only) following a caret (^).


Resource Compiler Error RC2153

hex constants must have at least 1 hex digit

An empty hexadecimal constant was found.


Resource Compiler Error RC2154

control character out of range [^A - ^Z]

A control character in the ACCELERATORS statement is invalid. The character following the caret (^) must be between A and Z, inclusive.


Resource Compiler Error RC2155

invalid accelerator

An event field in the ACCELERATORS statement was not recognized or was more than two characters in length.


Resource Compiler Error RC2156

expected string or constant accelerator command

RC was not able to determine what kind of key is being set up for the accelerator. The event field in the ACCELERATORS statement might be invalid.


Resource Compiler Error RC2157

expected comma in accelerator table

The Resource Compiler requires a comma between the event and idvalue fields in the ACCELERATORS statement.


Resource Compiler Error RC2159

invalid accelerator type [ASCII or VIRTKEY]

The type field in the ACCELERATORS statement must contain either the ASCII or VIRTKEY value.


Resource Compiler Error RC2160

## cannot occur at the beginning of a macro definition

A macro definition began with a token-pasting operator (##).


Resource Compiler Error RC2161

## cannot occur at the end of a macro definition

A macro definition ended with a token-pasting operator (##).


Resource Compiler Error RC2162

expected macro formal parameter

The token following a stringizing operator (#) was not a formal parameter name.


Resource Compiler Error RC2163

accelerator type required [ASCII or VIRTKEY]

The type field in the ACCELERATORS statement must contain either the ASCII or VIRTKEY value.


Resource Compiler Error RC2164

unexpected value in RCDATA

The raw-data values in the RCDATA statement must be integers or strings, each separated by a comma. Make sure you did not leave out a comma or leave out a quotation mark around a string.


Resource Compiler Error RC2165

string not found in DLGINCLUDE statement

The statement did not specify a valid include file.

The DLGINCLUDE statement must use the following syntax:

DLGINCLUDE “filename.h”


Resource Compiler Error RC2166

numeric value expected at line

The resource on the specified line must be a numeric value.


Resource Compiler Error RC2167

unrecognized VERSIONINFO field; BEGIN or comma expected

An unrecognized field was found in the FIXED part of a VERSIONINFO structure declaration. A VERSIONINFO field must be DWORDS separated by a comma.


Resource Compiler Error RC2168

resource too large

The size limitation of a resource was exceeded. This limit does not apply to cursors, icons, bitmaps, or other file-based resources.


Resource Compiler Error RC2169

resource file filename is not in 2.03 format

The specified resource used a format earlier than version 2.03. The resource file must be converted or re-created using the format for version 3.00 or later.


Resource Compiler Error RC2170

bitmap file filename is not in 3.00 format

Bitmaps using the Windows version 2.x format cannot be used in version 3.x resource files. The bitmap must be redrawn or converted to 3.x format.


Resource Compiler Error RC2171

unknown DIB header format

The bitmap header is not a BITMAPCOREHEADER or BITMAPINFOHEADER structure.


Resource Compiler Error RC2174

bitmap file filename is not in 2.03 format

A bitmap used a format earlier than version 2.03. The bitmap must be converted or redrawn using the format for version 3.00 or later.


Resource Compiler Error RC2175

resource file filename is not in 3.00 format

The specified resource used a format earlier than version 3.00. The resource file must be converted or recreated using the format for version 3.00 or later.


Resource Compiler Error RC2176

old DIB in filename. Pass it through SDKPAINT.

An old format Device Independent Bitmap was found in the specified file. It should be converted to the current format. The SDKPAINT application provided in the Windows 3.0 SDK, or an equivalent application, can be used to do this.


Resource Compiler Error RC2177

constant too big

A constant value was too large to be represented in the type to which it was assigned.


Resource Compiler Error RC2180

unable to open temporary file

The Resource Compiler/Visual C++ was unable to open a temporary file. The probable cause is either that you do not have write permissions for the directory, or that the directory does not exist. The Resource Compiler/Visual C++ attempts to use these files in the directory specified by the TMP environment variable or the current directory if none is specified.


Resource Compiler Error RC2181

duplicate font ID fontID

The specified font ID was already defined.


Resource Compiler Error RC2189

#error : error

This error is used to display other error messages.


Resource Compiler Error RC2235

too many arguments supplied

An expression contained more formal parameters than expected.


Resource Compiler Error RC2236

required parameter missing

An expression contained fewer formal parameters than expected.


Resource Compiler Warning RC4000

UNKNOWN WARNING

Note the circumstances of the warning, try to isolate the problem and create a reproducible test case, then consult the technical-support help file or the technical-support section in one of your manuals.


Resource Compiler Warning RC4002

too many actual parameters for macro 'identifier'

The number of actual parameters specified with the given identifier was greater than the number of formal parameters given in the macro definition of the identifier.

The additional actual parameters were collected but ignored during expansion of the macro.


Resource Compiler Warning RC4003

not enough actual parameters for macro 'identifier'

The number of actual parameters specified with the given identifier was less than the number of formal parameters given in the macro definition of the identifier.

When a formal parameter is referenced in the definition and the corresponding actual parameter has not been provided, empty text is substituted in the macro expansion.


Resource Compiler Warning RC4004

missing close parenthesis after 'defined'

An opening parenthesis was not matched with a closing parenthesis.


Resource Compiler Warning RC4005

'identifier' : macro redefinition

The given identifier was defined twice. The compiler used the second macro definition.

This warning can be caused by defining a macro on the command line and in the code with a #define directive. It also can be caused by macros imported from include files.

To eliminate the warning, either remove one of the definitions or use an #undef directive before the second definition.


Resource Compiler Warning RC4006

#undef expected an identifier

The name of the identifier whose definition was to be removed was not given with the #undef directive. The #undef directive was ignored.


Resource Compiler Warning RC4009

string too big, trailing chars truncated

A string was too large to fit in a buffer. Trailing characters were truncated and the remaining string was used.


Resource Compiler Warning RC4011

identifier truncated to 'identifier'

An identifier was too long and was truncated to the name shown in the warning.


Resource Compiler Warning RC4012

float constant in a cross compilation

A float constant may not have the same value on different target platforms.


Resource Compiler Warning RC4067

unexpected characters following 'token' directive - newline expected

A newline character should follow the specified token.


Resource Compiler Warning RC4079

unexpected token 'token'

Check the syntax of the line containing the specified token.


Resource Compiler Warning RC4093

unescaped newline in character constant in inactive code

The constant expression of an #if, #elif, #ifdef, or #ifndef preprocessor directive evaluated to zero, making the code that follows inactive. Within that inactive code, a newline character appeared within a set of single or double quotation marks.

All text until the next double quotation mark was considered to be within a character constant.


Resource Compiler Warning RC4111

unexpected token 'string'

Check the syntax of the line containing the specified token.


Resource Compiler Warning RC4117

macro name 'macro' is reserved, macro ignored

The specified macro was given a reserved name.


Resource Compiler Warning RC4203

SHIFT or CONTROL used without VIRTKEY

In an accelerator table resource, SHIFT or CONTROL require VIRTKEY. Because SHIFT and CONTROL are indicated as flag bits in a VIRTKEY type accelerator, they cannot exist independent from a VIRTKEY.


Resource Compiler Warning RC4204

ASCII character not equivalent to virtual key code

A string literal was used for the virtual key code in a VIRTKEY type accelerator.

This warning lets you continue, but be aware that the accelerator keys generated may not match the string you indicated. (VIRTKEYs use different key codes than ASCII accelerators.)

While string literals are syntactically valid, you can only ensure that you get the accelerator you want by using the VK_* #define values in WINDOWS.H.


Resource Compiler Warning RC4205

string literal longer than 256 - stored anyway

A literal sting exceeded 256 characters. It was stored intact.


Resource Compiler Warning RC4206

name string too long - truncated at 256

A name string exceeded the limit of 256 characters. It was truncated to 256 characters.


Resource Compiler Warning RC4207

type string too long - truncated at 256

A type string exceeded the limit of 256 characters. It was truncated to 256 characters.


Resource Compiler Warning RC4208

title string too long - truncated at 256

A title string exceeded the limit of 256 characters. It was truncated to 256 characters.


Resource Compiler Warning RC4413

cannot determine file type for 'filename' : assuming 8-bit ASCII

The type of specified file is not known to the Resource Compiler. It was compiled as an 8-bit ASCII file.


Resource Compiler Errors RW1004 through RW4004

The following topics cover resource compiler error RW1004 through warning RW4004.


Resource Compiler Fatal Error RW1004

Unexpected end of file

This error can be caused by omitting the linefeed and carriage-return characters on the last line of a text file.


Resource Compiler Fatal Error RW1009

Error creating resource-name

Could not create specified .RES file. Make sure it is not being created on a read-only drive. Use the /V option to find out whether the file is being created.


Resource Compiler Fatal Error RW1016

RC terminating after preprocessor errors

The Resource Compiler halted due to other errors. Fix the other errors and recompile.


Resource Compiler Fatal Error RW1021

I/O error reading file

The Resource Compiler was not able to read a file. Check that the drive containing the file is available and that the file is valid.


Resource Compiler Fatal Error RW1022

I/O error writing file

The Resource Compiler could not write to a file.

This error may be caused by insufficient disk space. You must have free space equivalent to about twice the size of the executable file you are creating.

Other possible reasons for this error are:

  • Writing to a read-only volume

  • Writing to a bad sector

  • A sharing violation


Resource Compiler Fatal Error RW1023

I/O error writing file, drive full

The Resource Compiler could not write a file to a drive because the drive was full.

You must have free space equivalent to about twice the size of the executable file you are creating.


Resource Compiler Fatal Error RW1025

Out of far heap memory

There wasn’t enough memory. Try not running any memory-resident software that might be taking up too much space. Use the CHKDSK program to find out how much memory you have.

If you are creating a large resource file, you can split the resource script into two files. After creating two .RES files, use the MS-DOS command to join them together. For example:

copy first.res /b + second.res /b full.res


Resource Compiler Fatal Error RW1030

Output Error

The output error can be caused by any of following conditions:

  • Errors occurred when linking file

    LINK failed. See Set Linker Options and Linker Reference for more information about linking an executable.

  • .EXE file too large; relink with higher /ALIGN value

    f the .EXE file is larger than 800K, you should use the /ALIGN:32 value on your LINK line.

  • File not created by LINK

    You must create the .EXE file with a version of Microsoft LINK later than 5.0 or with LINKW.

  • Invalid .EXE file

    Make sure that the linker created the .EXE file correctly and that the file exists. You can check the .EXE file with the Microsoft EXEHDR utility.

  • Not a Microsoft Windows format .EXE file

    Make sure that the linker created the .EXE file correctly and that the file exists. You can check the .EXE file with the Microsoft EXEHDR utility.

  • The EXETYPE of this program is not Windows

    The EXETYPE WINDOWS statement did not appear in the .DEF file.

  • Unable to create destination

    RC was not able to create the destination file. Make sure that there is enough disk space and that you have write permission on the volume.

  • Unable to open exe-file

    RC could not open this .EXE file. Make sure that the linker created it correctly and that the file exists.


Resource Compiler Error RW2001

Invalid directive in preprocessed RC file

The RC file contains a #pragma directive.

Use the #ifndef preprocessor directive with the RC_INVOKED constant that the Resource Compiler defines when it processes an include file. Place the #pragma directive inside a block of code that is not processed when the RC_INVOKED constant is defined. Code in the block is processed only by the C/C++ compiler and not by the Resource Compiler. The following sample code demonstrates this technique:

#ifndef RC_INVOKED
#pragma pack(2)  // C/C++ only, ignored by Resource Compiler
#endif

The #pragma preprocessor directive has no meaning in an .RC file. The #include preprocessor directive is used frequently in an .RC file to include a header file (either a project-based custom header file or a standard header file provided by Microsoft with one of its products). Some of these include files contain the #pragma directive. Because a header file can include one or more other header files, the file that contains the offending #pragma directive may not be immediately obvious.

The #ifndef RC_INVOKED technique can control including header files in project-based header files.


Resource Compiler Error RW2002

Parsing error

The parsing error can be caused by any of following conditions:

  • Accelerator type required (ASCII or VIRTKEY)

    The type field in the ACCELERATORS statement must contain either the ASCII or VIRTKEY value.

  • BEGIN expected in accelerator table

    The BEGIN keyword must immediately follow the ACCELERATORS keyword.

  • BEGIN expected in dialog

    The BEGIN keyword must immediately follow the DIALOG keyword.

  • BEGIN expected in menu

    The BEGIN keyword must immediately follow the MENU keyword.

  • BEGIN expected in RCData

    The BEGIN keyword must immediately follow the RCDATA keyword.

  • BEGIN keyword expected in string table

    The BEGIN keyword must immediately follow the STRINGTABLE keyword.

  • Cannot re-use string constants

    You are using the same value twice in a STRINGTABLE statement. Make sure you are not mixing overlapping decimal and hexadecimal values. Each ID in a STRINGTABLE must be unique. For maximum efficiency use contiguous constants that start on a multiple of 16.

  • Control character out of range [^A - ^Z]

    A control character in the ACCELERATORS statement is invalid. The character following the caret (^) must be between A and Z, inclusive.

  • Empty menus not allowed

    An END keyword appears before any menu items are defined in the MENU statement. Empty menus are not permitted by the Resource Compiler. Make sure you do not have any open quotation marks within the MENU statement.

  • END expected in dialog

    The END keyword must occur at the end of a DIALOG statement. Make sure there are no open quotes left from the preceding statement.

  • END expected in menu

    The END keyword must come at the end of a MENU statement. Make sure you do not have any open quotation marks or a mismatched pair of BEGIN and END statements.

  • Expected comma in accelerator Table

    RC requires a comma between the event and idvalue fields in the ACCELERATORS statement.

  • Expected control class name

    The class field of a CONTROL statement in the DIALOG statement must be one of the following types: BUTTON, COMBOBOX, EDIT, LISTBOX, SCROLLBAR, STATIC, or user-defined. Make sure the class is spelled correctly.

  • Expected font face name

    The typeface field of the FONT option in the DIALOG statement must be an ASCII character string enclosed in double quotation marks. This field specifies the name of a font.

  • Expected ID value for menuitem

    The MENU statement must contain a menuID field, which specifies the name or number that identifies the menu resource.

  • Expected menu string

    Each MENUITEM and POPUP statement must contain a text field, which is a string enclosed in double quotation marks that specifies the name of the menu item or pop-up menu. A MENUITEM SEPARATOR statement requires no quoted string.

  • Expected numeric command value

    RC was expecting a numeric idvalue field in the ACCELERATORS statement. Make sure that you have used a #define constant to specify the value and that the constant is spelled correctly.

  • Expected numeric constant in string table

    A numeric constant, defined in a #define statement, must immediately follow the BEGIN keyword in a STRINGTABLE statement.

  • Expected numeric point size

    The pointsize field of the FONT option in the DIALOG statement must be an integer point size value.

  • Expected numerical dialog constant

    A DIALOG statement requires integer values for the x, y, width, and height fields. Make sure that these values are included after the DIALOG keyword and that they are not negative.

  • Expected string in STRINGTABLE

    A string is expected after each stringid value in a STRINGTABLE statement.

  • Expected string or constant accelerator command

    RC was not able to determine what kind of key is being set up for the accelerator. The event field in the ACCELERATORS statement might be invalid.

  • Expecting number for ID

    Expecting a number for the id field of a control statement in the DIALOG statement. Make sure you have a number or #define statement for the control ID.

  • Expecting quoted string in dialog class

    The class field of the CLASS option in the DIALOG statement must be an integer or a string, enclosed in double quotation marks.

  • Expecting quoted string in dialog title

    The captiontext field of the CAPTION option in the DIALOG statement must be an ASCII character string enclosed in double quotation marks.

  • File not found: filename

    The file specified in the RC command line was not found. Check to see whether the file has been moved to another directory and whether the filename or path is typed correctly. Files are searched for using the INCLUDE environment variable or the Visual Workbench setting, if available.

  • Font names must be ordinals

    The pointsize field in the FONT statement must be an integer, not a string.

  • Invalid accelerator

    An event field in the ACCELERATORS statement was not recognized or was more than two characters in length.

  • Invalid accelerator type (ASCII or VIRTKEY)

    The type field in the ACCELERATORS statement must contain either the ASCII or VIRTKEY value.

  • Invalid control character

    A control character in the ACCELERATORS statement is invalid. A valid control character consists of one letter (only) following a caret (^).

  • Invalid control type

    Each control statement in a DIALOG statement must be one of the following: CHECKBOX, COMBOBOX, CONTROL, CTEXT, DEFPUSHBUTTON, EDITTEXT, GROUPBOX, ICON, LISTBOX, LTEXT, PUSHBUTTON, RADIOBUTTON, RTEXT, SCROLLBAR. Make sure these control statements are spelled correctly.

  • Invalid type

    The resource type was not among the types defined in the WINDOWS.H file.

  • Text string or ordinal expected in control

    The text field of a CONTROL statement in the DIALOG statement must be either a text string or an ordinal reference to the type of control is expected. If using an ordinal, make sure that you have a #define statement for the control.

  • Mismatched parentheses

    Make sure you have closed every open parenthesis in the DIALOG statement.

  • Unexpected value in RCData

    The raw-data values in the RCDATA statement must be integers or strings, each separated by a comma. Make sure you did not leave out a comma or leave out a quotation mark around a string.

  • Unknown menu subtype

    The item-definition field of the MENU statement can contain only MENUITEM and POPUP statements.


Resource Compiler Error RW2003

Generation Error

General errors can be caused by any of following conditions:

  • Error: Bitmap file resource-file is not in 3.00 format

    Bitmaps using the Windows version 2.x format cannot be used in version 3.x resource files. The bitmap must be redrawn or converted to 3.x format.

  • Error: Old DIB in resource-name. Pass it through SDKPAINT

    A Device Independent Bitmap (DIB) in the specified resource is not compatible with the Windows 3.0 format. The bitmap must be redrawn or converted to the 3.x format.

  • Error: Resource file resouce-name is not in 3.00 format

    An icon or cursor in the specified resource used a format from a previous version of Windows. The icon or cursor must be redrawn or converted to the 3.x format.

  • Unknown DIB header format

    The bitmap header is not a BITMAPCOREHEADER or BITMAPINFOHEADER structure.

  • Unable to initialize symbol information

    This error occurs only in Visual C++. The probable cause is that you have too many open files or you cannot open or write to the data files needed for Visual C++ to import the symbols in your script. Visual C++ attempts to create these files in the directory specified by the TMP environment variable or the current directory if none is specified.

  • Unable to save symbol information

    This error occurs only in Visual C++. The probable cause is that you have too many open files or you cannot close or write to the data files needed for Visual C++ to import the symbols in your script. Visual C++ attempts to use these files in the directory specified by the TMP environment variable or the current directory if none is specified.

  • Bitmap file resource file is not in 2.03 format

    A bitmap used a format earlier than version 2.03. The bitmap must be converted or redrawn using the format for version 3.00 or later.

  • Resource too large

    For Windows 3.1 a resource cannot exceed approximately 65000 bytes. If your resource does, then you will not be able to compile it with Visual C++ or the command-line resource compiler. This limit does not apply to cursors, icons, bitmaps, or other file-based resources.

  • Resource file is not in 3.00 format

    A cursor or icon used a format earlier than version 3.00. The resource must be converted or redrawn using the format for version 3.00 or later.

  • Unable to open temporary file

    The Resource Compiler/Visual C++ was unable to open a temporary file. The probable cause is either that you do not have write permissions for the directory or that the directory does not exist. The Resource Compiler/Visual C++ attempts to use these files in the directory specified by the TMP environment variable or the current directory if none is specified.


Resource Compiler Warning RW4001

.EXE processing options (/L /M /P /T /K /E /31 or /30)

.EXE processing options (/L /M /P /T /K /E /31 or /30) were specified when no executable file would be processed. These options can only be used when the result is an .EXE file (not a .RES file).


Resource Compiler Warning RW4003

SHIFT or CONTROL used without VIRTKEY

In an accelerator table resource, SHIFT or CONTROL require VIRTKEY. Because SHIFT and CONTROL are indicated as flag bits in a VIRTKEY type accelerator, they cannot exist independent from a VIRTKEY.


Resource Compiler Warning RW4004

ASCII character not equivalent to virtual key code

A string literal was used for the virtual key code in a VIRTKEY type accelerator.

This warning lets you continue, but be aware that the accelerator keys generated may not match the string you indicated. (VIRTKEYs use different key codes than ASCII accelerators.)

While string literals are syntactically valid, you can only ensure that you get the accelerator you want by using the VK_* #define values in WINDOWS.H.


CVTRES Errors CVT1100 through CVT4001

The following topics cover error CVT1100 through warning CVT4001.


CVTRES Fatal Error CVT1100

duplicate resource -- type:type, name:name, language:language, flags:flags, size:size

The given resource was specified more than once.


CVTRES Fatal Error CVT1101

cannot open filename for reading

CVTRES could not open and read the given file.

One of the following may be a cause:

  • The file does not exist. Check the spelling of the filename and path.

  • The file does not have read permission.

  • The file was opened or deleted by another process.

  • There was not enough space on disk.


CVTRES Fatal Error CVT1102

out of memory; size bytes required

There was not enough memory for CVTRES to complete the operation.


CVTRES Fatal Error CVT1103

cannot read filename

An unrecoverable error occurred when CVTRES attempted to read the given file.

Possibly the file is corrupt.


CVTRES Fatal Error CVT1104

cannot get location in file

CVTRES could not determine the current location in the file.

Possibly the file is corrupt.


CVTRES Fatal Error CVT1105

cannot seek in file

CVTRES could not go to a location in the file.

Possibly the file is corrupt.


CVTRES Fatal Error CVT1106

cannot write to file

An unrecoverable error occurred when CVTRES attempted to write to the given file.


CVTRES Fatal Error CVT1107

filename is corrupt

The given file is not a valid resource file.


CVTRES Fatal Error CVT1108

cannot open filename for writing

CVTRES could not open and write to the given file.

One of the following may be a cause:

  • The file does not exist. Check the spelling of the filename and path.

  • The file does not have write permission.

  • The file was opened or deleted by another process.

  • There was not enough space on disk.


CVTRES Warning CVT4001

machine type not specified; assumed type

CVTRES did not find a machine specification. It assumed the given machine type. If the default is incorrect, rerun CVTRES using the /MACHINE option.


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

    • Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

    • Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

    • Remedy: Insert the MSDN Library CD into the CD-ROM drive.


Example: Obtaining Information About Querydefs

Classes for Obtaining Information About Collections

Object | Class (structure)
Database | CDaoDatabaseInfo
Field | CDaoFieldInfo
Index | CDaoIndexInfo
Index Field (field that is part of an index object) | CDaoIndexFieldInfo
Parameter | CDaoParameterInfo
QueryDef | CDaoQueryDefInfo
Relation | CDaoRelationInfo
Relation Field (field that is part of a relation object) | CDaoRelationFieldInfo
TableDef | CDaoTableDefInfo
Workspace | CDaoWorkspaceInfo

One additional DAO object, the error object, is handled somewhat differently in MFC, so you don’t use the technique described in this article to work with error objects. For information, see class CDaoException in the Class Library Reference.

Example: Obtaining Information About Querydefs

This example shows how to loop through the QueryDefs collection of a CDaoDatabase object and obtain information about the QueryDefs in the collection. The example searches the QueryDefs collection for a particular named query, called “Senior Students”, so it can then extract other information about the query — such as its SQL string or query type.

// pDB is a pointer to a CDaoDatabase object
// Allocate a CDaoQueryDefInfo object to
// receive the information
CDaoQueryDefInfo queryinfo;
int nQueries = pDB->GetQueryDefCount( );
for ( int i = 0; i < nQueries; i++ )
{
    pDB->GetQueryDefInfo( i, queryinfo );
    if ( queryinfo.m_strName == "Senior Students" )
    {
        // Get other information about the query ...
        // ...
        break;
    }
}

The code iterates through the collection, retrieving information about each object until the desired named query is found. Note that DAO collections are zero-based.

Tip Some MFC DAO class functions use CDaoXInfo structures for input parameters as well as for output parameters. In those cases, you assign values to a CDaoXInfo object, then pass the object to the function.

Constants for Specifying the Levels of Information You Want

The syntax of the GetQueryDefInfo member function used in the example under Example: Obtaining Information About Querydefs is:

void GetQueryDefInfo( int nIndex, CDaoQueryDefInfo& queryinfo, DWORD dwInfoOptions = AFX_DAO_PRIMARY_INFO );

In the example, the queryinfo parameter returns a reference to a CDaoQueryDefInfo object. The example accepts the default value, AFX_DAO_PRIMARY_INFO, for the dwInfoOptions parameter, which specifies what information to return. The following table lists the options in this case.

Constants for Specifying the Levels of Information You Want

Constant | Meaning
AFX_DAO_PRIMARY_INFO | Primary level of information; in the querydef case, this includes Name and Type.
AFX_DAO_SECONDARY_INFO | Primary information plus a secondary level of information; in the querydef case, this would include Date Created, Date of Last Update, Returns Records, and Updatable.
AFX_DAO_ALL_INFO | Primary and secondary information plus additional information: in the querydef case, this would include SQL, Connect, and ODBCTimeout.

The items listed in column 2 of the table correspond to data members of the appropriate CDaoXInfo structure and, beneath that, to DAO properties.

Notice that the levels of information are cumulative: if you specify a higher level, such as secondary or all, you get the lower levels as well. For details about what information you can obtain for each collection type, see the appropriate GetXInfo functions. The functions are listed in the table Classes for Obtaining Information About Collections.

Caution In many cases, the information obtained with the AFX_DAO_ALL_INFO option can be time-consuming or otherwise costly to obtain. For example, getting a count of the records in a recordset can be time-consuming. Use this option with care.

See Also DAO: Where Is..., DAO Collections


Standard Commands

The framework defines many standard command messages. The IDs for these commands typically take the form:

ID_Source_Item

where Source is usually a menu name and Item is a menu item. For example, the command ID for the New command on the File menu is ID_FILE_NEW. Standard command IDs are shown in bold type in the documentation. Programmer-defined IDs are shown in a font that is different from the surrounding text.

The following is a list of some of the most important commands supported:

File Menu Commands

New, Open, Close, Save, Save As, Page Setup, Print Setup, Print, Print Preview, Exit, and most-recently-used files.

Edit Menu Commands

Clear, Clear All, Copy, Cut, Find, Paste, Repeat, Replace, Select All, Undo, and Redo.

View Menu Commands

Toolbar and Status Bar.

Window Menu Commands

New, Arrange, Cascade, Tile Horizontal, Tile Vertical, and Split.

Help Menu Commands

Index, Using Help, and About.

OLE Commands (Edit Menu)

Insert New Object, Edit Links, Paste Link, Paste Special, and typename Object (verb commands).

The framework provides varying levels of support for these commands. Some commands are supported only as defined command IDs, while others are supported with thorough implementations. For example, the framework implements the Open command on the File menu by creating a new document object, displaying an Open dialog box, and opening and reading the file. In contrast, you must implement commands on the Edit menu yourself, since commands like ID_EDIT_COPY depend on the nature of the data you are copying.

For more information about the commands supported and the level of implementation provided, see Technical Note 22. The standard commands are defined in the file AFXRES.H.


Topic Not Found

No matching topic was found. Some possible reasons and remedies are as follows:

  • The file (.chm) that contains the destination topic is not in the expected location.

    Remedy: Rerun the MSDN Library Setup.

  • The file (.chm) that contains the current topic or destination topic is out-of-date and the link is no longer valid.

    Remedy: Install the latest version of the MSDN Library.

  • The MSDN Library CD is not in the CD-ROM drive.

    Remedy: Insert the MSDN Library CD into the CD-ROM drive.


Creating an INF File

The INF file is a text file that specifies the files (such as DLLs or other OCXs) that need to be present or downloaded for your control to run. An INF file allows you to bundle all the needed files in one compressed CAB file. By default, files with the same version numbers as existing files on the user's hard disk will not be downloaded. For more information about INF files and their options, including how to create platform-independent INF files, see http://www.microsoft.com/intdev/security/authcode/codedwld.htm#pack on the World Wide Web, or the Platform SDK section Setup and System Management Services\Setup API\Overview\INF Files. The Platform SDK is included with the MSDN online documentation.

As an example, the following INF will be used to create a CAB file for the ATL Polygon control. You can build POLYGON.DLL by downloading the ATL POLYGON sample files from the Visual C++ CD and building a MinSize version. If you build a MinSize version of the Polygon control, you need one additional DLL, ATL.DLL. Since ATL.DLL needs to be registered before POLYGON.DLL, put the ATL.DLL first in the INF file:

; Sample INF file for POLYGON.DLL
[version]
; version signature (same for both NT and Win95) do not remove
signature="$CHICAGO$"
AdvancedINF=2.0

[Add.Code]
polygon.dll=polygon.dll
atl.dll=atl.dll

; needed DLL
[atl.dll]
file-win32-x86=thiscab
FileVersion=2,00,0,7024
DestDir=11
RegisterServer=yes

[polygon.dll]
file-win32-x86=thiscab
clsid={4CBBC676-507F-11D0-B98B-000000000000}
FileVersion=1,0,0,1
RegisterServer=yes
; end of INF file

This INF specifies that ATL.DLL with the given version needs to be installed on the system. If ATL.DLL doesn't exist already on the system, it will be downloaded from the CAB file created with this INF. "thiscab" is a keyword meaning the CAB containing this INF. You can also download a needed DLL from an HTTP location by specifying an absolute or relative path, for example:

file-win32-x86=http://www.mysite.com/mydir/NEEDED.DLL

The keyword "file-win32-x86" identifies the platform as x86 specific.

You can get the version number of a file by clicking the right mouse button on the file in Windows NT or Windows 95 Explorer. Select Properties from the list that appears, then select the Version tab on the dialog box that appears. You will sometimes need to insert an extra 0 in the file version. For example, the version number for the ATL.DLL is shown as 2.00.7024 in the dialog box. This becomes 2, 00, 0, 7024 in the INF file.

The "DestDir" is where the directory where the file will be loaded: 11 specifies the system directory WINDOWS/SYSTEM or WINNT/SYSTEM32; 10 specifies the windows directory, WINDOWS or WINNT. If no DestDir is specified (typical case), code is installed in the fixed OCCACHE directory.

The "clsid" is the CLSID of the control to be installed.

Once you have created an INF file, run the CABARC utility (available in the CAB&SIGN directory on the Visual C++ CD) to create the CAB file. You should run CABARC in the directory that contains your source files. On the command line, put the source files in the order they appear in the INF and the INF file last. For example, to make a CAB file for the Polygon control from the INF above, use the following command:

C:\CAB&SIGN\CABARC -s 6144 POLYGON.CAB ATL.DLL POLYGON.DLL POLYGON.INF

The POLYGON.CAB file contains a compressed version of ATL.DLL and POLYGON.DLL along with the information needed to extract them in the POLYGON.INF file.

For an example of building a CAB file that downloads an MFC control, see http://www.microsoft.com/visualc/download/mfcdnld.htm. The DLL files you need to include with an MFC control are MSVCRT.DLL, MFC42.DLL, and OLEPRO32.DLL.


Making a Test Software Publisher Certificate

You can use the MAKECERT and CERT2SPC utilities provided in the CAB&SIGN directory on the Visual C++ CD to make a test Software Publisher Certificate. Note that this test SPC is not valid for software publishing, but can be used to test code signing.

To make a private key file called MYKEY.PVK and a company certificate called CERT.CER, run the MAKECERT utility with the following command:

C:\CAB&SIGN\MAKECERT -u:MyKey -n:CN=MySoftwareCompany -k:MYKEY.PVK CERT.CER

MyKey is the name you give to your key and MySoftwareCompany is the name of your company. Note that the MAKECERT utility is case sensitive to command-line options, so you must use lowercase -u, -n, and -k. The value for the -n option must be an uppercase CN=.

To create a test Software Publisher Certificate (SPC) called CERT.SPC, run the CERT2SPC utility with the following command:

C:\CAB&SIGN\CERT2SPC C:\CAB&SIGN\ROOT.CER CERT.CER CERT.SPC

Note that the CERT.SPC file is created from the CERT.CER file you created with MAKECERT and from the ROOT.CER file provided in the CAB&SIGN directory.


Running the CABARC Utility

The CABARC utility is available in the CAB&SIGN directory on the CD. For example:

C:\CAB&SIGN\CABARC -s 6144 n MYCTL.CAB NEEDED1.DLL NEEDED2.DLL MYCTL.OCX MYCTL.INF

CABARC creates a CAB file called MYCTL.CAB.

You should run CABARC in the directory that contains your source files (the INF, OCX, and DLL files). The files to be archived in the CAB file should be listed on the command line in the same order they are listed in the INF file. In the example above, the INF file should list NEEDED1.DLL first, then NEEDED2.DLL, and then MYCTL.OCX.

The -s option reserves space in the cabinet for code signing. The n command specifies that you want to create a CAB file. For a list of CABARC commands and options, type CABARC alone on the command line:

C:\CAB&SIGN\CABARC